1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4 #include "SUMA_suma.h"
5 #include "thd_segtools_fNM.h"
6 #include "SUMA_SegOpts.h"
7 #include "SUMA_SegFunc.h"
8 #include "SUMA_CoordMatch.h"
9 #include "SUMA_gts.h"
10 
usage_SurfMatch(SUMA_GENERIC_ARGV_PARSE * ps,int detail)11 void usage_SurfMatch (SUMA_GENERIC_ARGV_PARSE *ps, int detail)
12 {
13       static char FuncName[]={"usage_SurfMatch"};
14       char * s = NULL, *sio=NULL, *st = NULL, *sts = NULL;
15       int i;
16       s = SUMA_help_basics();
17       sio  = SUMA_help_IO_Args(ps);
18       printf (
19    "\n"
20    "Usage: SurfMatch <-i_TYPE BASE> <-i_TYPE INSURF> <-prefix PREFIX> \n"
21    "                 [-sv SURF_VOL] [-warp WARP]\n"
22    "  -i_TYPE BASE: BASE is the reference surface to which nodes will be\n"
23    "                registered. The BASE surface is the first surface on the\n"
24    "                command line.\n"
25    "  -i_TYPE INSURF: Surface whose nodes will be affine transformed as to\n"
26    "                  minimize their shortest distance to BASE.\n"
27    "  -depthlimit DL: Exclude from cost computations nodes in INSURF that \n"
28    "                  are more than DL from the top node along the principal\n"
29    "                  direction closest to the Z axis.\n"
30    "  -reduce_ref RED: Reduce first mesh to speed up computations.\n"
31    "                   If RED is between 0 and 1.0, then the new surface\n"
32    "                   will approximately have RED * N_Nodes\n"
33    "                   If RED > 1.0 then RED is the approximate number of\n"
34    "                   nodes in the reduced mesh.\n"
35    "  -warp WARP: Set the type of affine warp allowed. \n"
36    "              Choose from the following:\n"
37    "                 sho: For shift only.\n"
38    "                 sro: For shift + rotate\n"
39    "                 srs: For shift + rotate + scale\n"
40    /* "                 aff: For affine general.\n" */
41    "  -city: Use City Block instead of Euclidian distance\n"
42    "\n"
43    /* Need an option that just takes point, not necessarily a second
44       surface.
45       Need an option to provide cmask  */
46    "Example:\n"
47    "         SurfMatch -i std.6rh.pial.asc -i std.6lh.pial.asc -warp sro\n"
48    "         suma -onestate -i std.6rh.pial.asc -i std.6lh.pial.asc \\\n"
49    "                        -i SurfMatch.gii   \n"
50    "\n");
51       SUMA_free(s); s = NULL; SUMA_free(st); st = NULL;
52       SUMA_free(sio); sio = NULL;
53 
54       printf("       Ziad S. Saad SSCC/NIMH/NIH saadz@mail.nih.gov     \n");
55       exit(0);
56 }
57 
58 SUMA_GENERIC_PROG_OPTIONS_STRUCT *
SUMA_SurfMatch_ParseInput(char * argv[],int argc,SUMA_GENERIC_ARGV_PARSE * ps)59    SUMA_SurfMatch_ParseInput( char *argv[], int argc,
60                               SUMA_GENERIC_ARGV_PARSE *ps)
61 {
62    static char FuncName[]={"SUMA_SurfMatch_ParseInput"};
63    SUMA_GENERIC_PROG_OPTIONS_STRUCT *Opt=NULL;
64    int kar;
65    SUMA_Boolean brk;
66    SUMA_Boolean LocalHead = NOPE;
67 
68    SUMA_ENTRY;
69 
70    Opt = SUMA_Alloc_Generic_Prog_Options_Struct();
71    Opt->s=NULL;
72    Opt->flt1 = 1.0;
73    Opt->b1 = 0;
74    Opt->efrac = 0.0;
75    kar = 1;
76    brk = NOPE;
77    while (kar < argc) { /* loop accross command ine options */
78       /*fprintf(stdout, "%s verbose: Parsing command line...\n", FuncName);*/
79       if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
80           usage_SurfMatch(ps, strlen(argv[kar])>3?1:0);
81           exit (0);
82       }
83 
84       SUMA_SKIP_COMMON_OPTIONS(brk, kar);
85 
86 
87       if (!brk && (strcmp(argv[kar], "-warp") == 0))
88       {
89          if (kar+1 >= argc)
90          {
91             fprintf (SUMA_STDERR, "need a string after -warp \n");
92             exit (1);
93          }
94          ++kar;
95                 if (!strcmp(argv[kar],"shift_only") ||
96                     !strcmp(argv[kar],"sho")) {
97             Opt->s = SUMA_copy_string("shft");
98          } else if (!strcmp(argv[kar],"shift_rotate") ||
99                     !strcmp(argv[kar],"sro")) {
100             Opt->s = SUMA_copy_string("shft+rot");
101          } else if (!strcmp(argv[kar],"shift_rotate_scale") ||
102                     !strcmp(argv[kar],"srs")) {
103             Opt->s = SUMA_copy_string("shft+rot+scl");
104          } else if (!strcmp(argv[kar],"affine_general") ||
105                     !strcmp(argv[kar],"aff")) {
106             Opt->s = SUMA_copy_string("shft+rot+scl+shr");
107          } else {
108             SUMA_S_Errv("Bad -warp parameter of %s\n"
109                         "Choose from sho, sro, srs, or aff\n",
110                         argv[kar]);
111             exit(1);
112          }
113          brk = YUP;
114       }
115 
116       if (!brk && (strcmp(argv[kar], "-city") == 0))
117       {
118          Opt->b1 = 1;
119          brk = YUP;
120       }
121 
122       if (!brk && (strcmp(argv[kar], "-prefix") == 0))
123       {
124          if (kar+1 >= argc)
125          {
126             fprintf (SUMA_STDERR, "need a number after -prefix \n");
127             exit (1);
128          }
129          Opt->out_prefix = SUMA_copy_string(argv[++kar]);
130 
131          brk = YUP;
132       }
133 
134       if (!brk && (strcmp(argv[kar], "-depthlimit") == 0))
135       {
136          if (kar+1 >= argc)
137          {
138             fprintf (SUMA_STDERR, "need a number after -depthlimit \n");
139             exit (1);
140          }
141          Opt->flt1 = atof(argv[++kar]);
142          brk = YUP;
143       }
144 
145       if (!brk && (strcmp(argv[kar], "-reduce_ref") == 0))
146       {
147          if (kar+1 >= argc)
148          {
149             fprintf (SUMA_STDERR, "need a number after -reduce_ref \n");
150             exit (1);
151          }
152          Opt->efrac = atof(argv[++kar]);
153          brk = YUP;
154       }
155 
156       if (!brk && (strcmp(argv[kar], "-debug") == 0))
157       {
158          if (kar+1 >= argc)
159          {
160             fprintf (SUMA_STDERR, "need a number after -debug \n");
161             exit (1);
162          }
163 
164          Opt->debug = atoi(argv[++kar]);
165          brk = YUP;
166       }
167 
168       if (!brk && !ps->arg_checked[kar]) {
169          fprintf (SUMA_STDERR,
170                   "Error SurfMatch: Option %s not understood\n", argv[kar]);
171          suggest_best_prog_option(argv[0], argv[kar]);
172          exit (1);
173       } else {
174          brk = NOPE;
175          kar ++;
176       }
177    }
178 
179    if (!Opt->out_prefix) {
180       Opt->out_prefix = SUMA_copy_string("SurfMatch.gii");
181       THD_force_ok_overwrite(1) ;
182    }
183 
184    if (!Opt->s) {
185       Opt->s = SUMA_copy_string("shft");
186    }
187    SUMA_RETURN(Opt);
188 }
189 
main(int argc,char * argv[])190 int main (int argc,char *argv[])
191 {/* Main */
192    static char FuncName[]={"SurfMatch"};
193    SUMA_GENERIC_PROG_OPTIONS_STRUCT *Opt;
194    SUMA_GENERIC_ARGV_PARSE *ps=NULL;
195    SUMA_SurfSpecFile *Spec = NULL;
196    int N_Spec=0, N_inmask;
197    byte *cmask=NULL;
198    SUMA_SurfaceObject *SO = NULL, *SOr=NULL;
199    SUMA_Boolean LocalHead = NOPE;
200 
201    SUMA_STANDALONE_INIT;
202    SUMA_mainENTRY;
203 
204    /* Allocate space for DO structure */
205    SUMAg_DOv = SUMA_Alloc_DisplayObject_Struct (SUMA_MAX_DISPLAYABLE_OBJECTS);
206    ps = SUMA_Parse_IO_Args(argc, argv, "-i;-t;-spec;-s;-sv;");
207 
208    if (argc < 2) {
209       usage_SurfMatch(ps, 0);
210       exit (1);
211    }
212 
213    Opt = SUMA_SurfMatch_ParseInput (argv, argc, ps);
214 
215    if (Opt->debug > 2) LocalHead = YUP;
216 
217    /* check on inputs */
218    if (ps->s_N_surfnames + ps->i_N_surfnames + ps->t_N_surfnames != 2) {
219       SUMA_S_Err("Must have two surfaces");
220       exit(1);
221    }
222 
223    Spec = SUMA_IO_args_2_spec(ps, &N_Spec);
224    if (N_Spec == 0) {
225       SUMA_S_Err("No surfaces found.");
226       exit(1);
227    }
228    if (N_Spec != 1) {
229       SUMA_S_Err("Multiple spec at input.");
230       exit(1);
231    }
232 
233    SOr = SUMA_Load_Spec_Surf_with_Metrics(Spec, 0, ps->sv[0], 1);
234    if (!SOr) {
235          fprintf (SUMA_STDERR,"Error %s:\n"
236                               "Failed to find surface\n"
237                               "in spec file. \n",
238                               FuncName );
239          exit(1);
240 
241    }
242 
243    if (Opt->efrac>0.0) {
244       SUMA_SurfaceObject *SOrr=NULL;
245       if (!(SOrr = SUMA_Mesh_Resample_nodes(SOr, Opt->efrac))) {
246          SUMA_S_Errv("Failed to resample initial mesh at %f\n",Opt->efrac);
247          exit(1);
248       }
249       SUMA_Free_Surface_Object(SOr); SOr=SOrr; SOrr=NULL;
250       SUMA_SurfaceMetrics_eng(SOr, "EdgeList|MemberFace", NULL, 0,
251                                           SUMAg_CF->DsetList);
252       if (!SOr->Label && !(SUMA_SurfaceFileName(SOr, NOPE))) {
253          SOr->Label = SUMA_copy_string("Le_Remaille");
254       }
255    }
256 
257    SO = SUMA_Load_Spec_Surf_with_Metrics(Spec, 1, ps->sv[0], 1);
258 
259    if (Opt->flt1 != 1.0) {
260       SUMA_LHv("Masking out nodes deeper than %f mm", Opt->flt1);
261       N_inmask = SUMA_NodeDepth(SO->NodeList, SO->N_Node, prjdir,  NULL,
262                                 Opt->flt1, &cmask, NULL);
263    } else {
264       N_inmask = SO->N_Node;
265    }
266 
267    SUMA_S_Notev("Have Reference %s %d nodes, input %s, %d nodes (%d in mask)\n",
268                   SOr->Label, SOr->N_Node, SO->Label, SO->N_Node, N_inmask);
269    if (Opt->b1) {
270       Opt->s = SUMA_append_replace_string(Opt->s,"City", " ; ", 1);
271    }
272    SUMA_AlignCoords(SO->NodeList, SO->N_Node, cmask, 1, SOr, Opt->s);
273 
274    /* write surface */
275    if (!SUMA_Save_Surface_Object_Wrap (Opt->out_prefix, NULL, SO,
276                                   SUMA_FT_NOT_SPECIFIED, SUMA_FF_NOT_SPECIFIED,
277                                   NULL)) {
278       SUMA_S_Err("Failed to write surface of whole head");
279       exit (1);
280    }
281 
282    if (SOr) SUMA_Free_Surface_Object(SOr); SOr = NULL;
283    if (SO) SUMA_Free_Surface_Object(SO); SO = NULL;
284 
285    if (cmask) SUMA_free(cmask); cmask=NULL;
286    if (ps) SUMA_FreeGenericArgParse(ps); ps = NULL;
287    if (N_Spec) {
288       int k=0;
289       for (k=0; k<N_Spec; ++k) {
290          if (!SUMA_FreeSpecFields(&(Spec[k]))) {
291             SUMA_S_Err("Failed to free spec fields");
292          }
293       }
294       SUMA_free(Spec); Spec = NULL; N_Spec = 0;
295    }
296    if (Opt) Opt = SUMA_Free_Generic_Prog_Options_Struct(Opt);
297    if (!SUMA_Free_CommonFields(SUMAg_CF))
298       SUMA_error_message(FuncName,"SUMAg_CF Cleanup Failed!",1);
299    exit(0);
300 
301 }
302