1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "../mrilib.h"
6 #include "cluster_floatNOMASK.h"
7 #include "thd_segtools_fNM.h"
8
9
10
display_help(int detail)11 static void display_help(int detail)
12 { printf ("3d+t Clustering segmentation, command-line version.\n");
13 printf (" Based on The C clustering library.\n");
14 printf (" Copyright (C) 2002 Michiel Jan Laurens de Hoon.\n");
15 printf ("USAGE: 3dkmeans [options]\n");
16 printf ("options:\n");
17 printf (" -v, --version Version information\n");
18 printf (" -f filename: Input data to be clustered. \n");
19 printf (" You can specify multiple filenames in sequence\n"
20 " and they will be catenated internally.\n"
21 " e.g: -f F1+orig F2+orig F3+orig ...\n"
22 " or -f F1+orig -f F2+orig -f F3+orig ...\n" );
23 printf (" -input filename: Same as -f\n");
24 printf(
25 " -mask mset Means to use the dataset 'mset' as a mask:\n"
26 " Only voxels with nonzero values in 'mset'\n"
27 " will be printed from 'dataset'. Note\n"
28 " that the mask dataset and the input dataset\n"
29 " must have the same number of voxels.\n"
30 " -mrange a b Means to further restrict the voxels from\n"
31 " 'mset' so that only those mask values\n"
32 " between 'a' and 'b' (inclusive) will\n"
33 " be used. If this option is not given,\n"
34 " all nonzero values from 'mset' are used.\n"
35 " Note that if a voxel is zero in 'mset', then\n"
36 " it won't be included, even if a < 0 < b.\n"
37 " -cmask 'opts' Means to execute the options enclosed in single\n"
38 " quotes as a 3dcalc-like program, and produce\n"
39 " produce a mask from the resulting 3D brick.\n"
40 " Examples:\n"
41 " -cmask '-a fred+orig[7] -b zork+orig[3] -expr step(a-b)'\n"
42 " produces a mask that is nonzero only where\n"
43 " the 7th sub-brick of fred+orig is larger than\n"
44 " the 3rd sub-brick of zork+orig.\n"
45 " -cmask '-a fred+orig -expr 1-bool(k-7)'\n"
46 " produces a mask that is nonzero only in the\n"
47 " 7th slice (k=7); combined with -mask, you\n"
48 " could use this to extract just selected voxels\n"
49 " from particular slice(s).\n"
50 " Notes: * You can use both -mask and -cmask in the same\n"
51 " run - in this case, only voxels present in\n"
52 " both masks will be dumped.\n"
53 " * Only single sub-brick calculations can be\n"
54 " used in the 3dcalc-like calculations -\n"
55 " if you input a multi-brick dataset here,\n"
56 " without using a sub-brick index, then only\n"
57 " its 0th sub-brick will be used.\n"
58 " * Do not use quotes inside the 'opts' string!\n"
59 "\n");
60 #if 0
61 /* Not implemented */
62 printf (" -cg a|m Specifies whether to center each row\n"
63 " in the data\n"
64 " a: Subtract the mean of each row\n"
65 " m: Subtract the median of each row\n"
66 " (default is no centering)\n");
67 printf (" -ng Specifies to normalize each row in the data\n"
68 " (default is no normalization)\n");
69 printf (" -ca a|m Specifies whether to center each column \n"
70 " in the data\n"
71 " a: Subtract the mean of each column\n"
72 " m: Subtract the median of each column\n"
73 " (default is no centering)\n");
74 printf (" -na Specifies to normalize each column in the data\n"
75 " (default is no normalization)\n");
76 #endif
77 printf (" -u jobname Allows you to specify a different name for the \n"
78 " output files.\n"
79 " (default is derived from the input file name)\n");
80 printf (" -prefix PREFIX Allows you to specify a prefix for the output \n"
81 " volumes. Default is the same as jobname\n"
82 " There are two output volumes, one for the cluster\n"
83 " membership and one with distance measures.\n"
84 " The distance dataset, mostly for debugging puposes\n"
85 " is formatted as follows:\n"
86 " Sub-brick 0: Dc = 100*(1-Ci)+100*Di/(Dmax)\n"
87 " with Ci the cluster number for voxel i, Di the \n"
88 " distance of voxel i to the centroid of its \n"
89 " assigned cluster, Dmax is the maximum distance in\n"
90 " cluster Ci.\n"
91 " Sub-bricks 1..k: Dc0k contains the distance of a\n"
92 " voxel's data to the centroid of cluster k.\n"
93 " Sub-brick k+1: Dc_norm = (1.0-Di/Ei)*100.0, where \n"
94 " Ei is the smallest distance of voxel i to \n"
95 " the remaining clusters that is larger than Di.\n");
96 printf (" -g [0..8] Specifies distance measure for clustering\n" );
97 printf (" Note: Weight is a vector as long as the signatures\n"
98 " and used when computing distances. However for the\n"
99 " moment, all weights are set to 1\n"
100 " 0: No clustering\n"
101 " 1: Uncentered correlation distance\n"
102 " Same as Pearson distance, except\n"
103 " the means of v and s are not removed\n"
104 " when computing correlation.\n"
105 " 2: Pearson distance\n"
106 " = (1-Weighted_Pearson_Correlation(v,s))\n"
107 " 3: Uncentered correlation distance, absolute value\n"
108 " Same as abs(Pearson distance), except\n"
109 " the means of v and s are not removed\n"
110 " when computing correlation.\n"
111 " 4: Pearson distance, absolute value\n"
112 " = (1-abs(Weighted_Pearson_Correlation(v,s)))\n"
113 " 5: Spearman's rank distance\n"
114 " = (1-Spearman_Rank_Correlation(v,s))\n"
115 " No weighting is used\n"
116 " 6: Kendall's distance\n"
117 " = (1-Kendall_Tau(v,s))\n"
118 " No weighting is used\n"
119 " 7: Euclidean distance between v and s\n"
120 " = 1/sum(weight) * sum(weight[i]*(v[i]-s[i])^2)\n"
121 " 8: City-block distance\n"
122 " = 1/sum(weight) * sum(weight[i]*abs(v[i]-s[i]))\n"
123 "\n"
124 " (default for -g is 1, 7 if input has one value per voxel)\n"
125 "\n");
126 #if 0
127 printf (" -k number Specifies whether to run k-means clustering\n"
128 " instead of hierarchical clustering, and the number\n"
129 " of clusters k to use. \n"
130 " Default is kmeans with k = 3 clusters\n");
131 #endif
132 printf (" -k number Specify number of clusters\n");
133 printf (" -remap METH Reassign clusters numbers based on METH:\n"
134 " NONE: No remapping (default)\n"
135 " COUNT: based on cluster size ascending\n"
136 " iCOUNT: COUNT, descending\n"
137 " MAG: based on ascending magnitude of centroid\n"
138 " iMAG: MAG, descending\n");
139 printf (" -labeltable LTFILE: Attach labeltable LTFILE to clustering\n"
140 " output. This labeltable will overwrite\n"
141 " a table that is taken from CLUST_INIT\n"
142 " should you use -clust_init option.\n");
143 printf (" -clabels LAB1 LAB2 ...: Provide a label for each cluster.\n"
144 " Labels cannot start with '-'.\n");
145 printf (" -clust_init CLUST_INIT: Specify a dataset to initialize \n"
146 " clustering. This option sets -r 0 .\n"
147 " If CLUST_INIT has a labeltable and \n"
148 " you do not specify one then CLUST_INIT's\n"
149 " table is used for the output\n");
150 #if 0
151 printf (" -c number Force the program to do hierarchical clsutering\n"
152 " and specifies the number of clusters for tree\n"
153 " cutting after hierarchical clustering.\n"
154 " Options -c and -k are mutually exclusive\n");
155 #endif
156 printf (" -r number For k-means clustering, the number of times the\n"
157 " k-means clustering algorithm is run\n"
158 " (default: 0 with -clust_init, 1 otherwise)\n");
159 /* printf (" -m [msca] Specifies which hierarchical clustering method to\n"
160 " use:\n"
161 " m: Pairwise complete-linkage\n"
162 " s: Pairwise single-linkage\n"
163 " c: Pairwise centroid-linkage\n"
164 " a: Pairwise average-linkage\n"
165 " (default: m)\n"); */
166 printf (" -rsigs SIGS Calculate distances from each voxel's signature\n"
167 " to the signatures in SIGS. \n"
168 " SIGS is a multi-column 1D file with each column\n"
169 " being a signature.\n"
170 " The output is a dset the same size as the input\n"
171 " with as many sub-bricks as there are columns in \n"
172 " SIGS.\n"
173 " With this option, no clustering is done.\n");
174 printf (" -verb verbose \n");
175 printf (" -write_dists Output text files containing various measures.\n"
176 " FILE.kgg.1D : Cluster assignments \n"
177 " FILE.dis.1D : Distance between clusters\n"
178 " FILE.cen.1D : Cluster centroids\n"
179 " FILE.info1.1D: Within cluster sum of distances\n"
180 " FILE.info2.1D: Maximum distance within each cluster\n"
181 " FILE.vcd.1D: Distance from voxel to its centroid\n");
182 printf (" -voxdbg I J K Output debugging info for voxel I J K\n");
183 printf (" -seed SEED Seed for the random number generator.\n"
184 " Default is 1234567\n");
185 EXRETURN;
186 }
187
188
189
190 /* ========================================================================= */
191
main(int argc,char ** argv)192 int main(int argc, char **argv)
193 {
194 int ii=0, ncol=0, nrow=0, nl=0, nc=0;
195 int i = 1;
196 char* filename[256];
197 int l = 0;
198 char method = 'm';
199 char cg = '\0';
200 char ca = '\0';
201 int ng = 0;
202 int na = 0;
203 char *prefix = NULL;
204 char *signame=NULL;
205 THD_3dim_dataset *in_set=NULL, *clust_set=NULL, *clust_init=NULL;
206 THD_3dim_dataset *mask_dset=NULL, *dist_set=NULL;
207 byte *cmask=NULL ; int ncmask=0 ;
208 byte *mask=NULL;
209 int nmask=-1, mnx=-1, mny=-1, mnz=-1, iset=0, N_iset=0, mnxyz=-1;
210 float mask_bot=666.0 , mask_top=-666.0 ;
211 OPT_KMEANS oc;
212 float *dvec=NULL, **D=NULL;
213 int n = 0, Ncoltot=0, nc0=0, nx=0, ny=0, nz=0;
214 char *prefixvcd = NULL, *clust_init_name=NULL;
215
216
217 mainENTRY("3dkmeans"); machdep();/* Used to be called 3dAclustering_fNM */
218 PRINT_VERSION("3dkmeans"); AUTHOR("avovk") ;
219
220 oc = new_kmeans_oc();
221
222 oc.r = -1;
223 oc.k = 0;
224 oc.kh = 0;
225 oc.jobname = NULL;
226 oc.distmetric = '*';
227 oc.verb = 0;
228 oc.rand_seed = 1234567;
229 oc.remap = NONE;
230 oc.user_labeltable=NULL;
231 oc.nclabels=0;
232
233 for (i=0; i<4; ++i) oc.voxdebug[i] = -1;
234 N_iset = 0;
235 filename[N_iset] = NULL;
236
237
238 i = 1;
239 while (i < argc)
240 { const char* const argument = argv[i];
241 i++;
242 if (strlen(argument)<2)
243 { printf("ERROR: missing argument\n");
244 RETURN(1);
245 }
246 if (argument[0]!='-')
247 { printf("ERROR: unknown argument %s\n", argument);
248 RETURN(1);
249 }
250 if(!strcmp(argument,"--version") || !strcmp(argument,"-v"))
251 { clusterlib_display_version();
252 RETURN(0);
253 }
254 if( !strcmp(argument,"--help")
255 || !strcmp(argument,"-h")
256 || !strcmp(argument,"-help") )
257 { display_help(strlen(argument) > 3 ? 2:1);
258 RETURN(0);
259 }
260 if( !strcmp(argument,"--verb")
261 || !strcmp(argument,"-verb") )
262 { oc.verb +=1;
263 continue;
264 }
265 if( !strcmp(argument,"--write_dists")
266 || !strcmp(argument,"-write_dists") )
267 { oc.writedists=1;
268 continue;
269 }
270 if( !strcmp(argument,"--remap")
271 || !strcmp(argument,"-remap") )
272 {
273 if (i<argc) {
274 if (!strcmp("COUNT",argv[i])) {
275 oc.remap = COUNT;
276 } else if (!strcmp("iCOUNT",argv[i])) {
277 oc.remap = iCOUNT;
278 } else if (!strcmp("MAG",argv[i])) {
279 oc.remap = MAG;
280 } else if (!strcmp("iMAG",argv[i])) {
281 oc.remap = iMAG;
282 } else if (!strcmp("NONE",argv[i])) {
283 oc.remap = NONE;
284 } else { printf ("Error reading command line argument for -remap\n");
285 RETURN(1);
286 }
287 } else {
288 printf ("Need parameter after -remap\n");
289 RETURN(1);
290 }
291 i++;
292 continue;
293 }
294 if(!strcmp(argument,"-cg"))
295 { if (i==argc || strlen(argv[i])>1 || !strchr("am",argv[i][0]))
296 { printf ("Error reading command line argument cg\n");
297 RETURN(1);
298 }
299 cg = argv[i][0];
300 i++;
301 continue;
302 }
303 if(!strcmp(argument,"-ca"))
304 { if (i==argc || strlen(argv[i])>1 || !strchr("am",argv[i][0]))
305 { printf ("Error reading command line argument ca\n");
306 RETURN(1);
307 }
308 ca = argv[i][0];
309 i++;
310 continue;
311 }
312 if(!strcmp(argument,"-labeltable"))
313 { if (i==argc)
314 { printf ("Error: Need filename after -labeltable\n");
315 RETURN(1);
316 }
317 oc.user_labeltable = argv[i];
318 i++;
319 continue;
320 }
321 if(!strcmp(argument,"-prefix"))
322 { if (i==argc)
323 { printf ("Error: Need name after -prefix\n");
324 RETURN(1);
325 }
326 prefix = strdup(argv[i]);
327 i++;
328 continue;
329 }
330 if(!strcmp(argument,"-clust_init"))
331 { if (i==argc)
332 { printf ("Error: Need dset after -clust_init\n");
333 RETURN(1);
334 }
335 clust_init_name = argv[i];
336 i++;
337 continue;
338 }
339 if(!strcmp(argument,"-voxdbg"))
340 { if (i+2==argc)
341 { printf ("Error: Need 3 integers after -voxedbg\n");
342 RETURN(1);
343 }
344 oc.voxdebug[0] = atoi(argv[i]);i++;
345 oc.voxdebug[1] = atoi(argv[i]);i++;
346 oc.voxdebug[2] = atoi(argv[i]);i++;
347 continue;
348 }
349
350 if(!strcmp(argument,"-rsigs"))
351 { if (i==argc)
352 { printf ("Error: Need name after -rsigs\n");
353 RETURN(1);
354 }
355 signame = argv[i];
356 i++;
357 continue;
358 }
359
360 if(!strcmp(argument,"-seed"))
361 { if (i==argc)
362 { printf ("Error: Need a +ve integer after -seed\n");
363 RETURN(1);
364 }
365 oc.rand_seed = atoi(argv[i]);
366 if (oc.rand_seed <=0) {
367 printf ("Error: seed must be > 0\n");
368 RETURN(1);
369 }
370 i++;
371 continue;
372 }
373
374 if( strncmp(argument,"-mask",5) == 0 ){
375 if( mask_dset != NULL )
376 ERROR_exit("Cannot have two -mask options!\n") ;
377 if( i >= argc )
378 ERROR_exit("-mask option requires a following argument!\n");
379 mask_dset = THD_open_dataset( argv[i] ) ;
380 if( mask_dset == NULL )
381 ERROR_exit("Cannot open mask dataset!\n") ;
382 if( DSET_BRICK_TYPE(mask_dset,0) == MRI_complex )
383 ERROR_exit("Cannot deal with complex-valued mask dataset!\n");
384 i++ ; continue ;
385 }
386
387 if( strncmp(argument,"-mrange",5) == 0 ){
388 if( i+1 >= argc )
389 ERROR_exit("-mrange option requires 2 following arguments!\n");
390 mask_bot = strtod( argv[ i] , NULL ) ;
391 mask_top = strtod( argv[++i] , NULL ) ;
392 if( mask_top < mask_top )
393 ERROR_exit("-mrange inputs are illegal!\n") ;
394 i++ ; continue ;
395 }
396
397 if( strcmp(argument,"-cmask") == 0 ){ /* 16 Mar 2000 */
398 if( i >= argc )
399 ERROR_exit("-cmask option requires a following argument!\n");
400 cmask = EDT_calcmask( argv[i] , &ncmask, 0 ) ;
401 if( cmask == NULL ) ERROR_exit("Can't compute -cmask!\n");
402 i++ ; continue ;
403 }
404
405 if(!strcmp(argument,"-ng"))
406 { ng = 1;
407 continue;
408 }
409 if(!strcmp(argument,"-na"))
410 { na = 1;
411 continue;
412 }
413
414 if(!strcmp(argument,"-f") || !strcmp(argument,"-input")) {
415 if (i==argc)
416 { printf ("Error reading command line argument -f (or -input): "
417 "no file name specified\n");
418 RETURN(1);
419 }
420 do {
421 filename[N_iset] = argv[i];
422 if (N_iset > 100) {
423 printf ("Error: Too many input files!\n");
424 RETURN(1);
425 }
426 ++N_iset; filename[N_iset] = NULL;
427 i++;
428 } while (i< argc && argv[i][0] != '-');
429 continue;
430 }
431 if(!strcmp(argument,"-clabels")) {
432 if (i==argc)
433 { printf ("Error reading command line argument -clabels: "
434 "no labels specified\n");
435 RETURN(1);
436 }
437 do {
438 oc.clabels[oc.nclabels] = argv[i];
439 if (oc.nclabels > 400) {
440 printf ("Error: Too many labels!\n");
441 RETURN(1);
442 }
443 ++oc.nclabels;
444 i++;
445 } while (i< argc && argv[i][0] != '-');
446 continue;
447 }
448
449 switch (argument[1])
450 { case 'l': l=1; break;
451 case 'u':
452 { if (i==argc)
453 { printf ("Error reading command line argument u: "
454 "no job name specified\n");
455 RETURN(1);
456 }
457 oc.jobname = clusterlib_setjobname(argv[i],0);
458 i++;
459 break;
460 }
461 #if 0
462 case 'f':
463 { if (i==argc)
464 { printf ("Error reading command line argument f: "
465 "no file name specified\n");
466 RETURN(1);
467 }
468 do {
469 filename[N_iset] = argv[i];
470 if (N_iset > 100) {
471 printf ("Error: Too many input files!\n");
472 RETURN(1);
473 }
474 ++N_iset; filename[N_iset] = NULL;
475 i++;
476 } while (i< argc && argv[i][0] != '-');
477 break;
478 }
479 #endif
480 case 'g':
481 { int g;
482 if (i==argc)
483 { printf ("Error reading command line argument g: parameter missing\n");
484 RETURN(1);
485 }
486 g = clusterlib_readnumber(argv[i]);
487 if (g < 0 || g > 9)
488 { printf ("Error reading command line argument g: "
489 "should be between 0 and 9 inclusive\n");
490 RETURN(1);
491 }
492 i++;
493 oc.distmetric = clusterlib_getmetric(g);
494 break;
495 }
496
497 case 'k':
498 { if (i==argc)
499 { printf ("Error reading command line argument k: "
500 "parameter missing\n");
501 RETURN(1);
502 }
503 if (oc.kh > 0) {
504 ERROR_message("-k and -c options are mutually exclusive\n");
505 RETURN(1);
506 }
507 oc.k = clusterlib_readnumber(argv[i]);
508 if (oc.k < 1)
509 { printf ("Error reading command line argument k: "
510 "a positive integer is required\n");
511 RETURN(1);
512 }
513 i++;
514 break;
515 }
516 case 'c':
517 { if (i==argc)
518 { printf ("Error reading command line argument c: parameter missing\n");
519 RETURN(1);
520 }
521 if (oc.k > 0) {
522 ERROR_message("-k and -c options are mutually exclusive\n");
523 RETURN(1);
524 }
525 oc.kh = clusterlib_readnumber(argv[i]);
526 if (oc.kh < 1)
527 { printf ("Error reading command line argument c: "
528 "a positive integer is required\n");
529 RETURN(1);
530 }
531 i++;
532 break;
533 }
534 case 'r':
535 { if (i==argc)
536 { printf ("Error reading command line argument r: parameter missing\n");
537 RETURN(1);
538 }
539 oc.r = clusterlib_readnumber(argv[i]);
540 if (oc.r < 0)
541 { printf ("Error reading command line argument r: "
542 "a >= 0 integer is required\n");
543 RETURN(1);
544 }
545 i++;
546 break;
547 }
548 case 'm':
549 { if (i==argc || strlen(argv[i])>1 || !strchr("msca",argv[i][0]))
550 { printf ("Error reading command line argument m: "
551 "should be 'm', 's', 'c', or 'a'\n");
552 RETURN(1);
553 }
554 method = argv[i][0];
555 i++;
556 break;
557 }
558 default:
559 printf ("Unknown option %s\n", argv[i-1]);
560 suggest_best_prog_option(argv[0], argv[i-1]);
561 RETURN(1);
562 }
563
564 }
565 if (argc < 2) {
566 printf ("Too few options!");
567 display_help(0);
568 RETURN(1);
569 }
570
571 if (oc.k <= 0 && oc.kh <= 0) oc.k = 3;
572
573 if (clust_init_name) {
574 if (oc.r > 0) {
575 ERROR_message("Can't use -clust_init and -r > 0");
576 RETURN(1);
577 } else {
578 oc.r = 0;
579 }
580 }
581
582 if (oc.r == -1) oc.r = 1;
583
584
585
586 if(oc.jobname == NULL) oc.jobname = clusterlib_setjobname(filename[0],1);
587
588 if (oc.nclabels && oc.nclabels != oc.k && oc.nclabels != oc.kh) {
589 ERROR_message("Have %d labels, but %d clusters\n",
590 oc.nclabels, oc.k > 0 ? oc.k : oc.kh);
591 RETURN(1);
592 }
593
594 /* load dsets and prepare array data for sending to clustering functions */
595
596 if (!prefix) {
597 prefix = (char *)calloc(strlen(oc.jobname)+15,sizeof(char));
598 sprintf(prefix,"%s.k%d",oc.jobname, oc.k);
599 THD_force_ok_overwrite(1) ; /* don't worry about overwriting */
600 }
601
602 /* ------------- Mask business -----------------*/
603 if( mask_dset == NULL ){
604 mask = NULL ;
605 if( oc.verb )
606 INFO_message("Using all voxels in the entire dataset (no mask)\n") ;
607 } else {
608 mnx = DSET_NX(mask_dset);
609 mny = DSET_NY(mask_dset);
610 mnz = DSET_NZ(mask_dset);
611 mnxyz = mnx*mny*mnz;
612 mask = THD_makemask( mask_dset , 0 , mask_bot, mask_top ) ;
613 if( mask == NULL ) ERROR_exit("Can't make mask") ;
614 nmask = THD_countmask( mnx*mny*mnz , mask ) ;
615 if( oc.verb )
616 INFO_message("%d voxels in the [%dx%dx%d] mask",nmask, mnx, mny, mnz) ;
617 if( nmask <= 0 ) ERROR_exit("No voxels in the mask!\n") ;
618 DSET_delete(mask_dset) ;
619 }
620
621 if( cmask != NULL ){
622 if( mask != NULL ){
623 if (mnxyz != ncmask) ERROR_exit("Mask and cmask dimension mismatch") ;
624 for( ii=0 ; ii < mnxyz ; ii++ )
625 mask[ii] = (mask[ii] && cmask[ii]) ;
626 free(cmask) ;
627 nmask = THD_countmask( mnxyz , mask ) ;
628 if( nmask <= 0 ) ERROR_exit("No voxels in the mask+cmask!\n") ;
629 if( oc.verb ) INFO_message("%d voxels in the mask+cmask\n",nmask) ;
630 } else {
631 mnx = -1; mny = -1; mnz = -1; /* unknown */
632 mnxyz = ncmask;
633 mask = cmask ;
634 nmask = THD_countmask( mnxyz , mask ) ;
635 if( nmask <= 0 ) ERROR_exit("No voxels in the cmask!\n") ;
636 if( oc.verb ) INFO_message("%d voxels in the cmask\n",nmask) ;
637 }
638 }
639
640 if (signame) {
641 MRI_IMAGE *im = NULL;
642 float *far = NULL;
643
644 /* catenate all input dsets */
645 if (N_iset == 1) {
646 in_set = THD_open_dataset(filename[0]);
647 CHECK_OPEN_ERROR(in_set,filename[0]) ;
648 if (oc.voxdebug[0] >= 0) {
649 /* setup for debugging */
650 oc.voxdebug[3] = oc.voxdebug[0] + oc.voxdebug[1]*DSET_NX(in_set) +
651 oc.voxdebug[2]*DSET_NX(in_set)*DSET_NY(in_set);
652 } else oc.voxdebug[3] = -1;
653 } else {
654 /* you'll need to read and catenate on the fly ... */
655 ERROR_exit( "Not ready to deal with more than one input.\n"
656 "Consdier catenating the input externally.\n"
657 "Let me know if it becomes annoying ...\n");
658 }
659
660 /* load the set of distance files */
661 im = mri_read_1D (signame);
662 far = MRI_FLOAT_PTR(im);
663 /* Now call distance function */
664 if (!thd_Adist ( in_set,
665 mask,
666 far, im->ny,
667 &dist_set ,
668 oc)) {
669 ERROR_exit("Failed in thd_Acluster");
670 }
671 if (im) mri_free(im); im = NULL; far = NULL;
672 /* add history to output data and write them out */
673 if( oc.verb && dist_set)
674 ININFO_message("\nWriting datasets: %s",prefix) ;
675 if (dist_set) {
676 EDIT_dset_items( dist_set , ADN_prefix , prefix, ADN_none);
677 tross_Copy_History( in_set , dist_set ) ;
678 tross_Make_History( "3dkmeans" , argc, argv , dist_set ) ;
679 DSET_write(dist_set); DSET_unload(dist_set);
680 DSET_delete(dist_set); dist_set = NULL;
681 }
682 } else {
683 /* Doing clustering function */
684 Ncoltot=0;
685 /* Read in dset(s) and create D */
686 for (iset = 0; iset < N_iset; ++iset) {
687 if (oc.verb) fprintf(stderr,"Reading %s's header (%d/%d), ",
688 filename[iset], iset+1, N_iset);
689 in_set = THD_open_dataset(filename[iset]);
690 CHECK_OPEN_ERROR(in_set,filename[iset]) ;
691 if (oc.voxdebug[0] >= 0) {
692 /* setup for debugging */
693 oc.voxdebug[3] = oc.voxdebug[0] + oc.voxdebug[1]*DSET_NX(in_set) +
694 oc.voxdebug[2]*DSET_NX(in_set)*DSET_NY(in_set);
695 } else oc.voxdebug[3] = -1;
696 if (iset == 0) {
697 ncol = DSET_NVALS(in_set);
698 nrow = DSET_NVOX(in_set);
699 nx = DSET_NX(in_set); ny = DSET_NY(in_set); nz = DSET_NZ(in_set);
700 if ( mask &&
701 ( ( (mnx >= 0 && mnx != DSET_NX(in_set)) ||
702 (mny >= 0 && mny != DSET_NY(in_set)) ||
703 (mnz >= 0 && mnz != DSET_NZ(in_set)) ) ||
704 ( mnxyz != nx*ny*nz ) ) ) {
705 ERROR_exit("Dimension mismatch between mask (%d=%dx%dx%d)\n"
706 " and input dset (%d=%dx%dx%d)",
707 mnxyz, mnx, mny,mnz, nx*ny*nz, nx,ny,nz);
708 }
709 if (!mask) nmask = DSET_NVOX(in_set);
710 } else { /* check for consistency with previous input */
711 if ( (nx != DSET_NX(in_set) ||
712 ny != DSET_NY(in_set) ||
713 nz != DSET_NZ(in_set) ) ) {
714 ERROR_exit( "Dimension mismatch between input dset"
715 " %s and preceding ones", filename[iset]);
716 }
717 ncol = DSET_NVALS(in_set);
718 }
719 if (oc.verb) fprintf(stderr," %d cols\n ",
720 ncol);
721 Ncoltot += ncol;
722 /* get rid of dset */
723 DSET_delete (in_set);
724 }
725
726 if (oc.distmetric == '*') {
727 if (Ncoltot == 1) oc.distmetric = 'e';
728 else oc.distmetric = 'u';
729 }
730
731 /* Now allocate for D */
732 D = (float **)calloc(sizeof(float*), nmask);
733 for (ii=0;ii<(nmask);++ii) {
734 if (!(D[ii] = (float *)calloc(sizeof(float), Ncoltot))) {
735 fprintf(stderr,"ERROR: Failed while allocating %dx%d float matrix\n",
736 nmask, Ncoltot);
737 RETURN(1);
738 }
739 }
740
741 dvec = (float * )malloc(sizeof(float)*Ncoltot) ; /* array to hold series
742 longer than needed, but
743 less hassle*/
744 nc0 = 0;
745 for (iset = 0; iset < N_iset; ++iset) {
746 if (oc.verb)
747 fprintf(stderr,"Patience, rereading %s...\n", filename[iset]);
748 in_set = THD_open_dataset(filename[iset]);
749 DSET_load(in_set) ; ncol = DSET_NVALS(in_set);
750
751 if (oc.verb) {
752 ININFO_message("Filling cols [%d..%d] of D(%dx%d) (mask=%p).\n",
753 nc0,nc0+ncol-1, nmask, Ncoltot, mask);
754 }
755 ii = 0;
756 for (nl=0; nl<DSET_NVOX(in_set); ++nl) {
757 if (!mask || mask[nl]) {
758 THD_extract_array( nl , in_set , 0 , dvec ) ;
759 for (nc=0; nc<ncol; ++nc) D[ii][nc0+nc] = dvec[nc];
760 ++ii;
761 }
762 }
763 nc0 += ncol;
764 if (iset != N_iset-1) DSET_delete(in_set);
765 else DSET_unload(in_set);
766 }
767 free(dvec); dvec = NULL;
768
769 /* Load initialization */
770 if (clust_init_name) {
771 if (oc.verb) fprintf(stderr,"Reading %s's header, ",
772 clust_init_name);
773 if (!(clust_init = THD_open_dataset(clust_init_name))) {
774 ERROR_exit("Failed to read initialization dset %s\n",
775 clust_init_name);
776 }
777 DSET_load(clust_init) ;
778 CHECK_OPEN_ERROR(clust_init,clust_init_name) ;
779 }
780
781 /* Now call clustering function */
782 if (!thd_Acluster ( in_set,
783 mask, nmask,
784 &clust_set,
785 &dist_set ,
786 clust_init,
787 oc, D, Ncoltot)) {
788 ERROR_exit("Failed in thd_Acluster");
789 }
790
791 /* freedom */
792 if (D) {
793 for (ii=0; ii<nmask; ++ii) if (D[ii]) free(D[ii]);
794 free(D); D = NULL;
795 }
796 /* avovk; make prefix for other datasets, based on input prefix */
797
798 n = 1 + strlen(prefix) + strlen("_vcd");
799 prefixvcd = (char *)malloc(n*sizeof(char));
800 sprintf (prefixvcd, "%s_vcd", prefix);
801
802
803 /* add history to output data and write them out */
804 if( oc.verb &&
805 (clust_set || dist_set))
806 ININFO_message("\nWriting dataset: %s %s",prefix, prefixvcd) ;
807 if (clust_set) {
808 EDIT_dset_items( clust_set , ADN_prefix , prefix, ADN_none);
809 tross_Copy_History( in_set , clust_set ) ;
810 tross_Make_History( "3dkmeans" , argc, argv , clust_set ) ;
811 DSET_write(clust_set); DSET_unload(clust_set);
812 DSET_delete(clust_set); clust_set = NULL;
813 }
814 ININFO_message("\nWriting dataset: %s", prefixvcd) ;
815 if (dist_set) {
816 EDIT_dset_items( dist_set , ADN_prefix , prefixvcd, ADN_none);
817 tross_Copy_History( in_set , dist_set ) ;
818 tross_Make_History( "3dkmeans" , argc, argv , dist_set ) ;
819 DSET_write(dist_set);
820 DSET_unload(dist_set);
821 DSET_delete(dist_set);
822 dist_set = NULL;
823 }
824
825 }
826
827 if (prefix) free(prefix); prefix=NULL;
828 if (mask) free(mask); mask = NULL;
829 if (oc.jobname) free(oc.jobname); oc.jobname = NULL;
830
831 fprintf (stderr,"\n");
832 RETURN(0);
833 }
834
835