1 /*****************************************************************************
2    Major portions of this software are copyrighted by the Medical College
3    of Wisconsin, 1994-2000, and are released under the Gnu General Public
4    License, Version 2.  See the file README.Copyright for details.
5 ******************************************************************************/
6 
7 /*
8    Plugin to edit an AFNI dataset.  This plugin is an interactive version
9    of batch program 3dmerge.
10 
11    File:     plug_edit.c
12    Author:   B. Douglas Ward
13    Date:     15 May 1997
14 
15 
16    Mod:      Added Erode/Dilate option to sever narrow connecting path
17              between clusters, by first eroding the outer layer of voxels,
18 	     then restoring voxels near the main body of the cluster.
19    Author:   B. Douglas Ward
20    Date:     18 June 1998
21 */
22 
23 
24 #include "afni.h"
25 
26 #ifndef ALLOW_PLUGINS
27 #  error "Plugins not properly set up -- see machdep.h"
28 #endif
29 
30 #define MEGA  1048576  /* 2^20 */
31 
32 char * EDIT_main( PLUGIN_interface * ) ;
33 
34 
35 static char helpstring[] =
36   "Purpose: AFNI plugin to edit data and return new dataset.\n"
37   "Inputs: \n"
38   " Dataset       Input and Output datasets\n"
39   "   Input       Input dataset that must already be in memory \n"
40   "   Prefix        Prefix for output file name \n"
41   "   Session       Write output into specified directory (default=./) \n"
42   " Clip          Clip intensities in range (lower,upper) to zero \n"
43   "   Unscaled      Do not apply any automatic scaling factor \n"
44   " Threshold     Use threshold sub-brick to censor the intensities \n"
45   " Blur          Gaussian blur using specified function width \n"
46   " Zero Vol UL   Zero out entries inside the 3D volume defined by: \n"
47   " Zero Vol LL     xLL <= x <=xUL,  yLL <= y <=yUL,  zLL <= z <= zUL \n"
48   " Cluster       Form clusters and clip off data not in clusters \n"
49   "   Type          Options for setting voxel intensities within a cluster \n"
50   "   Radius        Max. distance for 2 voxels to be connected in a cluster \n"
51   "   MinVol        Min. volume for a cluster to survive \n"
52   " Erode/Dilate  Sever narrow connecting paths between clusters \n"
53   "   % Voxels      Min. % of active 'neighbors' for a voxel to survive \n"
54   "   Dilate        Restore voxels near main body of cluster \n"
55   " Filter        Filter voxel intensities \n"
56   "   Type          Defines filter action \n"
57   "   Radius        Voxel intensity is effected by voxels within this radius\n"
58   " Multiply      Multiply intensities by the given factor\n"
59   " Datum         Coerce output data to be stored as the given type \n"
60   " Keep Thr      Copy the threshold sub-brick into the output dataset \n"
61   " Thr Blur      Apply Gaussian blur function to threshold data sub-brick \n"
62   " Thr Filter    Apply specified filter to threshold data sub-brick \n"
63   " Thr Datum     Coerce threshold data sub-brick to be stored as given type\n"
64   "Author -- BD Ward"
65 ;
66 
67 
68 /*---------------------------------------------------------------------------*/
69 /*
70   Set up the interface to the user
71 */
72 
73 
74 DEFINE_PLUGIN_PROTOTYPE
75 
PLUGIN_init(int ncall)76 PLUGIN_interface * PLUGIN_init( int ncall )
77 {
78   /*----- plugin option labels -----*/
79   char * boolean_types[2] = {"False", "True"};
80   char * blur_types[3] = {"Sigma", "RMS", "FWHM"};
81   char * cluster_types[7] = {"Keep", "Mean", "Max", "AMax", "SMax", "Size",
82                              "Order"};
83   char * filter_types[6] = {"Mean", "NZMean", "Max", "AMax", "SMax", "Aver" };
84   char * brick_types[2] = {"Intensity", "Threshold"};
85   char * datum_types[3] = {"Byte", "Short", "Float"};
86 
87   PLUGIN_interface * plint ;
88 
89 
90   if( ncall > 0 ) return NULL ;  /* only one interface */
91   CHECK_IF_ALLOWED("3DEDIT","3D Edit") ;  /* 30 Sep 2016 */
92 
93   /*-- set titles and call point --*/
94   plint = PLUTO_new_interface( "3D Edit" , "Dataset Editing" , helpstring ,
95 			       PLUGIN_CALL_VIA_MENU , EDIT_main  ) ;
96 
97   PLUTO_add_hint( plint , "Edit Dataset Contents" ) ;
98 
99   PLUTO_set_sequence( plint , "A:newdset:edit" ) ;
100 
101   /*---- line 1 of input: Dataset -----*/
102   PLUTO_add_option (plint, "Dataset", "Dataset", TRUE);
103   PLUTO_add_hint( plint , "Choose input and output" ) ;
104 
105   PLUTO_add_dataset (plint, "Input",
106 		     ANAT_ALL_MASK, FUNC_ALL_MASK,
107 		     DIMEN_3D_MASK | BRICK_ALLREAL_MASK);
108   PLUTO_add_hint( plint , "Choose input dataset" ) ;
109 
110   PLUTO_add_string (plint, "Prefix", 0, NULL, 19);
111   PLUTO_add_hint( plint , "Name output dataset" ) ;
112 
113   PLUTO_add_string (plint, "Session", 0, NULL, 19);
114   PLUTO_add_hint( plint , "Name output directory" ) ;
115 
116   /*----- line 2 of input: Options -----*/
117   PLUTO_add_option (plint, "Options", "Options", FALSE);
118   PLUTO_add_hint( plint , "Preprocessing steps" ) ;
119 
120   PLUTO_add_string (plint, "Thr->Int",  2, boolean_types, 0);
121   PLUTO_add_hint( plint , "Copy threshold over intensity brick?" ) ;
122 
123   PLUTO_add_string (plint, "No Neg",    2, boolean_types, 0);
124   PLUTO_add_hint( plint , "Zero out negative values?" ) ;
125 
126   PLUTO_add_string (plint, "Abs Value", 2, boolean_types, 0);
127   PLUTO_add_hint( plint , "Take absolute value?" ) ;
128 
129   /*----- line 3 of input: Clipping -----*/
130   PLUTO_add_option (plint, "Clip", "Clip", FALSE);
131   PLUTO_add_hint( plint , "Zero out values in some range" ) ;
132 
133   PLUTO_add_number (plint, "Lower", -99999, 99999, 0, 0, TRUE);
134   PLUTO_add_hint( plint , "Values above this => zero" ) ;
135 
136   PLUTO_add_number (plint, "Upper", -99999, 99999, 0, 0, TRUE);
137   PLUTO_add_hint( plint , "Values below this => zero" ) ;
138 
139   PLUTO_add_string (plint, "Unscaled?", 2, boolean_types, 0);
140   PLUTO_add_hint( plint , "Don't apply scaling factors?" ) ;
141 
142   /*----- line 4 of input: Threshold -----*/
143   PLUTO_add_option (plint, "Threshold", "Threshold" , FALSE);
144   PLUTO_add_hint( plint , "Zero out if threshold brick too small" ) ;
145 
146   PLUTO_add_number (plint, "Cutoff"   , 0, 10000, 2, 50, TRUE);
147   PLUTO_add_hint( plint , "Threshold values < this => 0" ) ;
148 
149   /*----- line 5 of input: Blurring -----*/
150   PLUTO_add_option (plint, "Blur", "Blur", FALSE);
151   PLUTO_add_hint( plint , "Gaussian convolution" ) ;
152 
153   PLUTO_add_string (plint, "Format", 3, blur_types, 0);
154   PLUTO_add_hint( plint , "How blur width is specified" ) ;
155 
156   PLUTO_add_number (plint, "Width(mm)", 0, 500, 1, 20, TRUE);
157   PLUTO_add_hint( plint , "Range of blurring function" ) ;
158 
159   /*----- line 6 of input: Zero Volume -----*/
160   PLUTO_add_option (plint, "Zero Vol UL", "Zero Vol UL", FALSE);
161   PLUTO_add_number (plint, "x Upper", -999, 999, 0, 0, TRUE);
162   PLUTO_add_number (plint, "y Upper", -999, 999, 0, 0, TRUE);
163   PLUTO_add_number (plint, "z Upper", -999, 999, 0, 0, TRUE);
164 
165   /*----- line 7 of input: Zero Volume -----*/
166   PLUTO_add_option (plint, "Zero Vol LL", "Zero Vol LL", FALSE);
167   PLUTO_add_number (plint, "x Lower", -999, 999, 0, 0, TRUE);
168   PLUTO_add_number (plint, "y Lower", -999, 999, 0, 0, TRUE);
169   PLUTO_add_number (plint, "z Lower", -999, 999, 0, 0, TRUE);
170 
171   /*----- line 8 of input: Cluster Parameters -----*/
172   PLUTO_add_option (plint, "Cluster", "Cluster", FALSE);
173   PLUTO_add_hint( plint , "Find and reject small clusters" ) ;
174 
175   PLUTO_add_string (plint, "Type", 7, cluster_types, 0);
176   PLUTO_add_hint( plint , "How to process data inside clusters" ) ;
177 
178   PLUTO_add_number (plint, "Radius(mm)", 0, 100, 1, 20, TRUE);
179   PLUTO_add_hint( plint , "Max distance between 'neighbors'" ) ;
180 
181   PLUTO_add_number (plint, "MinVol(ul)", 0, 1000, -1, 100, TRUE);
182   PLUTO_add_hint( plint , "Min size for cluster to survive" ) ;
183 
184   /*----- line 8a of input: Erosion/Dilation option -----*/ /* 18 June 1998 */
185   PLUTO_add_option (plint, "Erode/Dilate", "Erode/Dilate", FALSE);
186   PLUTO_add_hint (plint , "Sever narrow connecting paths between clusters");
187 
188   PLUTO_add_number (plint, "% Voxels", 0, 100, 0, 50, TRUE);
189   PLUTO_add_hint (plint,
190 		  "Min % of active 'neighbors' for a voxel to survive");
191 
192   PLUTO_add_string (plint, "Dilate?",  2, boolean_types, 0);
193   PLUTO_add_hint (plint , "Restore voxels near main body of cluster");
194 
195   /*----- line 9 of input: Filtering -----*/
196   PLUTO_add_option (plint, "Filter", "Filter", FALSE);
197   PLUTO_add_string (plint, "Type", 6, filter_types, 0);
198   PLUTO_add_number (plint, "Radius(mm)", 0, 100, 1, 20, TRUE);
199 
200   /*----- line 10 of input: Multiply -----*/
201   PLUTO_add_option (plint, "Multiply", "Multiply", FALSE);
202   PLUTO_add_number (plint, "Factor", -99999, 99999, 0, 1, TRUE);
203 
204   /*----- line 11 of input: Datum -----*/
205   PLUTO_add_option (plint, "Datum", "Datum", FALSE);
206   PLUTO_add_string (plint, "Type", 3, datum_types, 1);
207 
208   /*----- line 12 of input: Keep Threshold -----*/
209   PLUTO_add_option (plint, "Keep Thr", "Keep Thr", FALSE);
210   PLUTO_add_string (plint, "Keep?",  2, boolean_types, 0);
211 
212   /*----- line 13 of input: Threshold Blur -----*/
213   PLUTO_add_option (plint, "Thr Blur", "Thr Blur", FALSE);
214   PLUTO_add_string (plint, "Format", 3, blur_types, 0);
215   PLUTO_add_number (plint, "Width(mm)", 0, 100, 1, 20, TRUE);
216 
217   /*----- line 14 of input: Threshold Filter -----*/
218   PLUTO_add_option (plint, "Thr Filter", "Thr Filter", FALSE);
219   PLUTO_add_string (plint, "Type", 6, filter_types, 0);
220   PLUTO_add_number (plint, "Radius(mm)", 0, 100, 1, 20, TRUE);
221 
222   /*----- line 15 of input: Threshold Datum -----*/
223   PLUTO_add_option (plint, "Thr Datum", "Thr Datum", FALSE);
224   PLUTO_add_string (plint, "Type", 3, datum_types, 1);
225 
226   return plint ;
227 }
228 
229 
230 /*---------------------------------------------------------------------------*/
231 /*
232   Routine to read the editing options.
233 */
234 
EDIT_opts(PLUGIN_interface * plint,THD_3dim_dataset ** dset,EDIT_options * edopt,char ** new_prefix,char ** new_session,int * datum,int * keepthr,int * thrdatum)235 char * EDIT_opts
236 (
237   PLUGIN_interface * plint,       /* plugin interface */
238   THD_3dim_dataset ** dset,       /* original dataset */
239   EDIT_options * edopt,           /* the editing options */
240   char ** new_prefix,             /* output file name for edited dataset  */
241   char ** new_session,            /* output directory name */
242   int * datum,                    /* output intensity sub-brick data type */
243   int * keepthr,                  /* boolean for keep threshold sub-brick */
244   int * thrdatum                  /* output threshold sub-brick data type */
245 )
246 
247 {
248   char * tag;                     /* plugin option tag */
249   char * str;                     /* input string */
250   float rmm;                      /* cluster or filter radius (mm) */
251   float vmul;                     /* cluster minimum volume (ul) */
252   float thresh;                   /* threshold level */
253   MCW_idcode * idc ;              /* dataset id code */
254   int ival;                       /* integer value input */
255   float bot, top;                 /* clip option limits */
256   float blur;                     /* Gaussian blur function width */
257   float fval;                     /* input floating point value */
258   float dx, dy, dz, dxyz;         /* voxel dimensions */
259   float x1, x2, y1, y2, z1, z2;   /* zero volume limits */
260   float pv;                       /* pv % voxels within rmm must be active */
261 
262 
263   /*----- Check inputs from AFNI to see if they are reasonable-ish -----*/
264   if( plint == NULL )
265     return
266       "*********************\n"
267       "EDIT_opts: NULL input\n"
268       "*********************";
269 
270 
271   /*--------- go to first input line ---------*/
272   tag = PLUTO_get_optiontag(plint) ;
273   if( (tag==NULL) || (strcmp(tag,"Dataset") != 0) )
274     return
275       "*********************************\n"
276       "EDIT_opts: Bad dataset option tag\n"
277       "*********************************";
278 
279   idc  = PLUTO_get_idcode(plint) ;
280   (*dset) = PLUTO_find_dset(idc) ;
281   if( (*dset) == NULL )
282     return
283       "****************************\n"
284       "EDIT_opts: Bad input dataset\n"
285       "****************************";
286 
287   if (DSET_NUM_TIMES((*dset)) > 1)
288     return
289       "*************************************************\n"
290       "EDIT_opts: Unable to edit time-dependent datasets\n"
291       "*************************************************";
292 
293   /*----- get the dimensions -----*/
294   dx = fabs((*dset)->daxes->xxdel);
295   dy = fabs((*dset)->daxes->yydel);
296   dz = fabs((*dset)->daxes->zzdel);
297   dxyz  = dx*dy*dz ;
298 
299 
300   str = PLUTO_get_string(plint);
301   if (str != NULL)
302     {
303       if( ! PLUTO_prefix_ok(str) )
304 	return
305 	  "*********************\n"
306 	  "EDIT_opts: bad prefix\n"
307 	  "*********************";
308       else
309 	*new_prefix = str;
310     }
311 
312   str = PLUTO_get_string(plint);
313   if (str != NULL)
314     {
315       *new_session = str;
316     }
317 
318 
319   /*------ loop over remaining options, check their tags, process them -----*/
320   do
321     {
322       tag = PLUTO_get_optiontag(plint) ;
323       if( tag == NULL ) break ;
324 
325 
326       /*----- Miscellaneous Options -----*/
327       if (strcmp (tag, "Options") == 0)
328 	{
329 	  str = PLUTO_get_string(plint);
330 	  if (strcmp (str, "True") == 0)
331 	    {
332 	      if (DSET_THRESH_INDEX(*dset) < 0)
333 		return
334 		  "*********************************************\n"
335 		  "EDIT_opts: Dataset has no threshold sub-brick\n"
336 		  "*********************************************";
337 	      else
338 		edopt->thtoin = 1;
339 	    }
340 	  else
341 	    edopt->thtoin = 0;
342 
343 	  str = PLUTO_get_string(plint);
344 	  if (strcmp (str, "True") == 0)
345 	    edopt->noneg = 1;
346 	  else
347 	    edopt->noneg = 0;
348 
349 	  str = PLUTO_get_string(plint);
350 	  if (strcmp (str, "True") == 0)
351 	    edopt->abss = 1;
352 	  else
353 	    edopt->abss = 0;
354 
355 	  continue;
356 	}
357 
358 
359       /*----- Clip Option -----*/
360       if (strcmp(tag,"Clip") == 0)
361 	{
362 	  bot = PLUTO_get_number(plint);
363 	  top = PLUTO_get_number(plint);
364 	  str = PLUTO_get_string(plint);
365 
366 	  if (bot >= top)
367 	    return
368 	      "**********************************************************\n"
369 	      "EDIT_opts: First clip value must be less than second value\n"
370 	      "**********************************************************";
371 
372 	  edopt->clip_bot = bot;
373 	  edopt->clip_top = top;
374 
375 	  if (strcmp (str, "True") == 0)
376 	    edopt->clip_unscaled = 1;
377 	  else
378 	    edopt->clip_unscaled = 0;
379 
380 	  continue;
381 	}
382 
383 
384       /*----- Threshold Option -----*/
385       if (strcmp(tag,"Threshold") == 0)
386 	{
387 	  thresh = PLUTO_get_number(plint) ;
388 
389 	  if (thresh < 0.0)
390 	    return
391 	      "******************************\n"
392 	      "EDIT_opts: Bad Threshold input\n"
393 	      "******************************";
394 
395 	  if( thresh > 0.0 && DSET_THRESH_INDEX(*dset) < 0 )
396 	    return
397 	      "*********************************************\n"
398 	      "EDIT_opts: Dataset has no threshold sub-brick\n"
399 	      "*********************************************";
400 
401 	  edopt->thresh =  thresh;
402 	  edopt->thbot  = -thresh;  /* 26 Dec 2007 */
403 
404 	  continue;
405 	}
406 
407 
408       /*----- Blur Option -----*/
409       if (strcmp(tag,"Blur") == 0)
410 	{
411 	  str = PLUTO_get_string(plint);
412 	  blur = PLUTO_get_number(plint);
413 
414 	  if (blur <= 0.0 )
415 	    return
416 	      "*****************************\n"
417 	      "EDIT_opts: Illegal Blur input\n"
418 	      "*****************************";
419 
420 	  if (strcmp(str,"Sigma") == 0)
421 	    edopt->blur  = blur;
422 	  else
423 	    if (strcmp(str,"RMS") == 0)
424 	      edopt->blur = RMS_TO_SIGMA(blur);
425 	    else
426 	      if (strcmp(str,"FWHM") == 0)
427 		edopt->blur = FWHM_TO_SIGMA(blur);
428 	      else
429 		return
430 		  "******************************\n"
431 		  "EDIT_opts: Illegal Blur option\n"
432 		  "******************************";
433 
434 	  continue;
435 	}
436 
437 
438       /*----- Zero Volume Option -----*/
439       if (strcmp(tag, "Zero Vol UL") == 0)
440 	{
441 	  x2 = PLUTO_get_number(plint);
442 	  y2 = PLUTO_get_number(plint);
443 	  z2 = PLUTO_get_number(plint);
444 
445 	  tag = PLUTO_get_optiontag(plint);
446 	  if (strcmp(tag, "Zero Vol LL") == 0)
447 	    {
448 	      x1 = PLUTO_get_number(plint);
449 	      y1 = PLUTO_get_number(plint);
450 	      z1 = PLUTO_get_number(plint);
451 	    }
452 	  else
453 	    return
454 	      "***************************\n"
455 	      "EDIT_opts: Need Zero Vol LL\n"
456 	      "***************************";
457 
458 	  edopt->zv_x1 = x1;  edopt->zv_x2 = x2;
459 	  edopt->zv_y1 = y1;  edopt->zv_y2 = y2;
460 	  edopt->zv_z1 = z1;  edopt->zv_z2 = z2;
461 	  edopt->do_zvol = 1;
462 	  continue;
463 	}
464 
465 
466       if (strcmp(tag, "Zero Vol LL") == 0)
467 	{
468 	  return
469 	    "***************************\n"
470 	    "EDIT_opts: Need Zero Vol UL\n"
471 	    "***************************";
472 	}
473 
474 
475       /*----- Cluster Option -----*/
476       if (strcmp(tag,"Cluster") == 0)
477 	{
478 	  str = PLUTO_get_string(plint);
479 	  rmm  = PLUTO_get_number(plint) ;
480 	  vmul = PLUTO_get_number(plint) ;
481 
482 	  if ( (rmm < dx) && (rmm < dy) && (rmm < dz) )
483 	    return
484 	      "***********************************\n"
485 	      "EDIT_opts: Cluster rmm is too small\n"
486 	      "***********************************";
487 
488 	  if (vmul <= dxyz)
489 	    return
490 	      "************************************\n"
491 	      "EDIT_opts: Cluster vmul is too small\n"
492 	      "************************************";
493 
494 	  edopt->clust_rmm  = rmm;
495 	  edopt->clust_vmul = vmul;
496 
497 	  if (strcmp(str,"Keep") == 0)
498 	    edopt->edit_clust = ECFLAG_SAME;
499 	  else
500 	    if (strcmp(str,"Mean") == 0)
501 	      edopt->edit_clust = ECFLAG_MEAN;
502 	    else
503 	      if (strcmp(str,"Max") == 0)
504 		edopt->edit_clust = ECFLAG_MAX;
505 	      else
506 		if (strcmp(str,"AMax") == 0)
507 		  edopt->edit_clust = ECFLAG_AMAX;
508 		else
509 		  if (strcmp(str,"SMax") == 0)
510 		    edopt->edit_clust = ECFLAG_SMAX;
511 		  else
512 		    if (strcmp(str,"Size") == 0)
513 		      edopt->edit_clust = ECFLAG_SIZE;
514 		    else
515 		      if (strcmp(str,"Order") == 0)
516 			edopt->edit_clust = ECFLAG_ORDER;
517 		      else
518 		         if (strcmp(str,"Depth") == 0)
519 			   edopt->edit_clust = ECFLAG_DEPTH;
520                else
521 			return
522 			  "*********************************\n"
523 			  "EDIT_opts: Illegal Cluster option\n"
524 			  "*********************************";
525 
526 	  continue;
527 	}
528 
529 
530       /*----- Erosion/Dilation Option -----*/
531       if (strcmp(tag,"Erode/Dilate") == 0)
532 	{
533 	  pv  = PLUTO_get_number(plint);
534 	  if ((pv > 0.0) && (edopt->clust_rmm <= 0.0))
535 	    return
536 	      "******************************************************\n"
537 	      "EDIT_opts: Erode/Dilate requires use of Cluster option\n"
538 	      "******************************************************";
539 	  else
540 	    edopt->erode_pv  = pv / 100.0;
541 
542 	  str = PLUTO_get_string(plint);
543 	  if (strcmp (str, "True") == 0)
544 	    {
545 	      if (pv <= 0.0)
546 		return
547 		  "**********************************************\n"
548 		  "EDIT_opts: Dilate requires use of Erode option\n"
549 		  "**********************************************";
550 	      else
551 		edopt->dilate = 1;
552 	    }
553 	  else
554 	    edopt->dilate = 0;
555 
556 	  continue;
557 	}
558 
559 
560       /*----- Filter Option -----*/
561       if (strcmp(tag,"Filter") == 0)
562 	{
563 	  str = PLUTO_get_string(plint);
564 	  rmm  = PLUTO_get_number(plint) ;
565 
566 	  if ( (rmm < dx) && (rmm < dy) && (rmm < dz) )
567 	    return
568 	      "**********************************\n"
569 	      "EDIT_opts: Filter rmm is too small\n"
570 	      "**********************************";
571 
572 	  edopt->filter_rmm  = rmm;
573 
574 	  if (strcmp(str,"Mean") == 0)
575 	    edopt->filter_opt = FCFLAG_MEAN;
576 	  else
577 	    if (strcmp(str,"NZMean") == 0)
578 	      edopt->filter_opt = FCFLAG_NZMEAN;
579 	    else
580 	      if (strcmp(str,"Max") == 0)
581 		edopt->filter_opt = FCFLAG_MAX;
582 	      else
583 		if (strcmp(str,"AMax") == 0)
584 		  edopt->filter_opt = FCFLAG_AMAX;
585 		else
586 		  if (strcmp(str,"SMax") == 0)
587 		    edopt->filter_opt = FCFLAG_SMAX;
588                   else
589 		    if (strcmp(str,"Aver") == 0)       /* 07 Jan 1998 */
590 		      edopt->filter_opt = FCFLAG_AVER;
591 		    else
592 		      return
593 		        "********************************\n"
594 		        "EDIT_opts: Illegal Filter option\n"
595 		        "********************************";
596 
597 	  continue;
598 	}
599 
600 
601       /*----- Multiply Option -----*/
602       if (strcmp(tag,"Multiply") == 0)
603 	{
604 	  fval  = PLUTO_get_number(plint);
605 
606 	  if (fval == 0.0)
607 	    return
608 	      "*****************************\n"
609 	      "EDIT_opts: Bad Multiply input\n"
610 	      "*****************************";
611 
612 	  edopt->mult = fval;
613 
614 	  continue;
615 	}
616 
617 
618       /*----- Datum Type Option -----*/
619       if (strcmp(tag, "Datum") == 0)
620 	{
621 	  str = PLUTO_get_string(plint);
622 	  if (strcmp(str,"Byte") == 0)
623 	    *datum = MRI_byte;
624 	  else
625 	    if (strcmp(str,"Short") == 0)
626 	      *datum = MRI_short;
627 	    else
628 	      if (strcmp(str,"Float") == 0)
629 		*datum = MRI_float;
630 	      else
631 		{
632 		  return
633 		    "*****************************\n"
634 		    "EDIT_opts: Illegal Datum type\n"
635 		    "*****************************";
636 		}
637 
638 	  continue;
639 	}
640 
641 
642       /*----- Keep Threshold Option -----*/
643       if (strcmp(tag,"Keep Thr") == 0)
644 	{
645 	  str = PLUTO_get_string(plint);
646 	  if (strcmp (str, "True") == 0)
647 	    {
648 	      if (DSET_THRESH_INDEX(*dset) < 0)
649 		return
650 		  "*********************************************\n"
651 		  "EDIT_opts: Dataset has no threshold sub-brick\n"
652 		  "*********************************************";
653 	      else
654 		*keepthr = 1;
655 	    }
656 	  else
657 	    *keepthr = 0;
658 
659 	  continue;
660 	}
661 
662 
663       /*----- Threshold Blur Option -----*/
664       if (strcmp(tag,"Thr Blur") == 0)
665 	{
666 	  if (DSET_THRESH_INDEX(*dset) < 0)
667 	    return
668 	      "*********************************************\n"
669 	      "EDIT_opts: Dataset has no threshold sub-brick\n"
670 	      "*********************************************";
671 
672 	  str = PLUTO_get_string(plint);
673 	  blur = PLUTO_get_number(plint) ;
674 
675 	  if (blur <= 0.0 )
676 	    return
677 	      "***************************************\n"
678 	      "EDIT_opts: Illegal Threshold Blur input\n"
679 	      "***************************************";
680 
681 	  if (strcmp(str,"Sigma") == 0)
682 	    edopt->thrblur  = blur;
683 	  else
684 	    if (strcmp(str,"RMS") == 0)
685 	      edopt->thrblur = RMS_TO_SIGMA(blur);
686 	    else
687 	      if (strcmp(str,"FWHM") == 0)
688 		edopt->thrblur = FWHM_TO_SIGMA(blur);
689 	      else
690 		return
691 		  "******************************\n"
692 		  "EDIT_opts: Illegal Blur option\n"
693 		  "******************************";
694 
695 	  *keepthr = 1;
696 
697 	  continue;
698 	}
699 
700 
701       /*----- Threshold Filter Option -----*/
702       if (strcmp(tag,"Thr Filter") == 0)
703 	{
704 	  if (DSET_THRESH_INDEX(*dset) < 0)
705 	    return
706 	      "*********************************************\n"
707 	      "EDIT_opts: Dataset has no threshold sub-brick\n"
708 	      "*********************************************";
709 
710 	  str = PLUTO_get_string(plint);
711 	  rmm  = PLUTO_get_number(plint) ;
712 
713 	  if ( (rmm < dx) && (rmm < dy) && (rmm < dz) )
714 	    return
715 	      "**************************************\n"
716 	      "EDIT_opts: Thr Filter rmm is too small\n"
717 	      "**************************************";
718 
719 	  edopt->thrfilter_rmm  = rmm;
720 
721 	  if (strcmp(str,"Mean") == 0)
722 	    edopt->thrfilter_opt = FCFLAG_MEAN;
723 	  else
724 	    if (strcmp(str,"NZMean") == 0)
725 	      edopt->thrfilter_opt = FCFLAG_NZMEAN;
726 	    else
727 	      if (strcmp(str,"Max") == 0)
728 		edopt->thrfilter_opt = FCFLAG_MAX;
729 	      else
730 		if (strcmp(str,"AMax") == 0)
731 		  edopt->thrfilter_opt = FCFLAG_AMAX;
732 		else
733 		  if (strcmp(str,"SMax") == 0)
734 		    edopt->thrfilter_opt = FCFLAG_SMAX;
735                   else
736 		    if (strcmp(str,"Aver") == 0)       /* 07 Jan 1998 */
737 		      edopt->thrfilter_opt = FCFLAG_AVER;
738 		    else
739 		      return
740 		        "************************************\n"
741 		        "EDIT_opts: Illegal Thr Filter option\n"
742 		        "************************************";
743 
744 	  *keepthr = 1;
745 
746 	  continue;
747 	}
748 
749 
750       /*----- Threshold Datum Type Option -----*/
751       if (strcmp(tag, "Thr Datum") == 0)
752 	{
753 	  if (DSET_THRESH_INDEX(*dset) < 0)
754 	    return
755 	      "*********************************************\n"
756 	      "EDIT_opts: Dataset has no threshold sub-brick\n"
757 	      "*********************************************";
758 
759 	  str = PLUTO_get_string(plint);
760 	  if (strcmp(str,"Byte") == 0)
761 	    *thrdatum = MRI_byte;
762 	  else
763 	    if (strcmp(str,"Short") == 0)
764 	      *thrdatum = MRI_short;
765 	    else
766 	      if (strcmp(str,"Float") == 0)
767 		*thrdatum = MRI_float;
768 	      else
769 		{
770 		  return
771 		    "***************************************\n"
772 		    "EDIT_opts: Illegal Threshold Datum type\n"
773 		    "***************************************";
774 		}
775 
776 	  *keepthr = 1;
777 
778 	  continue;
779 	}
780 
781 
782       /*----- Illegal Option -----*/
783       else
784 	{
785 	  return
786 	    "***********************************\n"
787 	    "EDIT_opts: Illegal optiontag found!\n"
788 	    "***********************************";
789 	}
790 
791     } while(1) ;
792 
793 
794   /*---------- End of input options ----------*/
795 
796   return NULL;
797 }
798 
799 
800 /*---------------------------------------------------------------------------*/
801 /*
802   Main routine for this plugin (will be called from AFNI).
803 */
804 
EDIT_main(PLUGIN_interface * plint)805 char * EDIT_main( PLUGIN_interface * plint )
806 {
807   EDIT_options PE_edopt;
808   int PE_keepthr = 0;
809   int PE_datum = ILLEGAL_TYPE;
810   int PE_thdatum = ILLEGAL_TYPE;
811   int PE_be_quiet = 0;
812   char * PE_output_session = NULL;
813   char * PE_output_prefix = NULL;
814 
815 
816   int nx,ny,nz , nxyz , ii ,  ival;
817   THD_3dim_dataset * old_dset = NULL, * dset=NULL , * new_dset=NULL ;
818   int     datum ;
819   float fimfac , fimfacinv , first_fimfac , thrfac ;
820   int   output_datum , output_thdatum ;
821   int   input_datum  , input_thdatum , first_datum ;
822 
823   float thr_stataux[MAX_STAT_AUX] ;
824   char * str;
825 
826 
827 
828   /*-- set up for dataset editing --*/
829   INIT_EDOPT( &PE_edopt ) ;
830 
831 
832   /*----- read input options -----*/
833   str = EDIT_opts (plint, &old_dset, &PE_edopt,
834 		   &PE_output_prefix, &PE_output_session, &PE_datum,
835 		   &PE_keepthr, &PE_thdatum);
836   if (str != NULL)  return (str);
837 
838   /*----- make a copy of the original dataset -----*/
839   dset = PLUTO_copy_dset (old_dset, NULL);
840   DSET_unload (old_dset);
841 
842   /*----- get the dimensions -----*/
843   nx = dset->daxes->nxx ;
844   ny = dset->daxes->nyy ;
845   nz = dset->daxes->nzz ; nxyz = nx*ny*nz ;
846 
847 
848   ival        = DSET_PRINCIPAL_VALUE(dset) ;
849   input_datum = DSET_BRICK_TYPE(dset,ival) ;
850   if (PE_datum >= 0) output_datum = PE_datum ;
851   else               output_datum = input_datum ;
852 
853   new_dset = EDIT_empty_copy( dset ) ;
854 
855   EDIT_dset_items( new_dset ,
856 		   ADN_prefix , PE_output_prefix ,
857 		   ADN_label1 , PE_output_prefix ,
858 		   ADN_directory_name , PE_output_session ,
859 		   ADN_none ) ;
860   strcat( new_dset->self_name , "(PE)" ) ;
861 
862   { char * his = PLUTO_commandstring(plint) ;
863     tross_Copy_History( dset , new_dset ) ;
864     tross_Append_History( new_dset, his ) ; free(his) ;
865   }
866 
867   if( ! PE_keepthr && new_dset->dblk->nvals > 1 )
868     EDIT_dset_items( new_dset ,
869 		     ADN_nvals , 1 ,
870 		     ADN_func_type , FUNC_FIM_TYPE ,
871 		     ADN_none ) ;
872 
873   if ( PE_keepthr && ISFUNC(new_dset) && FUNC_HAVE_THR(new_dset->func_type) )
874     {
875       ii            = FUNC_ival_thr[dset->func_type] ;
876       input_thdatum = DSET_BRICK_TYPE(dset,ii) ;
877       if (PE_thdatum >= 0) output_thdatum = PE_thdatum ;
878       else                 output_thdatum = input_thdatum ;
879     }
880   else
881     {
882       output_thdatum = input_thdatum = ILLEGAL_TYPE ;
883     }
884 
885   if ( THD_is_file(new_dset->dblk->diskptr->header_name) )
886     {
887       fprintf(stderr,
888 	      "*** Output file %s already exists -- cannot continue!\n",
889 	      new_dset->dblk->diskptr->header_name ) ;
890       return("*** Output file already exists -- cannot continue!");
891       /*EXIT(1) ;*/
892     }
893 
894   if (! PE_be_quiet)
895     {
896       printf("-- editing input dataset in memory (%.1f MB)",
897 	          ((double)dset->dblk->total_bytes) / MEGA ) ;
898       fflush(stdout) ;
899     }
900 
901 
902   EDIT_one_dataset( dset , &PE_edopt ) ;  /* all the real work */
903 
904 
905   if (! PE_be_quiet)  { printf(".\n") ; fflush(stdout) ; }
906 
907 
908   /** Coerce the output data type into a new brick, if needed **/
909   ival = DSET_PRINCIPAL_VALUE(dset) ;
910   ii   = DSET_PRINCIPAL_VALUE(new_dset) ;
911 
912   if( input_datum == output_datum )
913     {
914       /*
915 	Attach the brick of the input dataset to the brick of the output.
916 	This isn't exactly kosher, but we are exiting almost immediately.
917       */
918       if (! PE_be_quiet)
919 	printf ("connecting edited input to be output \n");
920       mri_fix_data_pointer (DSET_ARRAY(dset,ival), DSET_BRICK(new_dset,ii));
921       DSET_BRICK_FACTOR(new_dset,ii) = DSET_BRICK_FACTOR(dset,ival);
922     }
923   else
924     {
925       /** Must create a new brick and do the conversion **/
926       void * dfim , * efim ;
927       float etop ;
928 
929       if(! PE_be_quiet)
930 	{
931 	  printf("-- coercing output datum to be %s\n",
932 		 MRI_TYPE_name[output_datum]);
933 	}
934 
935       efim = DSET_ARRAY(dset,ival) ;
936       dfim = (void *) XtMalloc( mri_datum_size(output_datum) * nxyz ) ;
937 
938       fimfac = EDIT_coerce_autoscale( nxyz , input_datum  , efim ,
939 				      output_datum , dfim  ) ;
940 
941       DSET_BRICK_FACTOR(new_dset,ii) = (fimfac != 0.0 && fimfac != 1.0)
942 	? 1.0/fimfac : 0.0 ;
943 
944       EDIT_substitute_brick( new_dset , ii , output_datum , dfim ) ;
945       mri_free( DSET_BRICK(dset,ival) ) ;
946     }
947 
948   /** Now do the threshold data **/
949 
950   if( output_thdatum >= 0 )
951     {
952       ival = FUNC_ival_thr[    dset->func_type] ;
953       ii   = FUNC_ival_thr[new_dset->func_type] ;
954 
955       if( input_thdatum == output_thdatum )
956 	{
957 	  if (! PE_be_quiet)
958 	    printf ("connecting input and output thresholds \n") ;
959 	  mri_fix_data_pointer (DSET_ARRAY(dset,ival),DSET_BRICK(new_dset,ii));
960 	  DSET_BRICK_FACTOR(new_dset,ii) = DSET_BRICK_FACTOR(dset,ival) ;
961 	}
962       else
963 	{
964 	  void * dfim , * efim ;
965 
966 	  if( ! PE_be_quiet )
967 	    {
968 	      printf("-- coercing threshold datum to be %s\n",
969 		     MRI_TYPE_name[output_thdatum]);
970 	    }
971 
972 	  efim = DSET_ARRAY(dset,ival) ;
973 	  dfim = (void *) XtMalloc( mri_datum_size(output_thdatum) * nxyz ) ;
974 
975 	  switch( output_thdatum )
976 	    {
977 	    default: fprintf(stderr,"** illegal output_thdatum = %d\n",
978 			     output_thdatum);
979 	      return("** illegal output_thdatum");
980 	      /* EXIT(1) ;*/
981 
982 	    case MRI_float:
983 	      fimfacinv = 0.0 ;
984 	      fimfac    = DSET_BRICK_FACTOR(dset,ival) ;
985 	      if( fimfac == 0.0 )
986 		{
987 		  fimfac = (input_thdatum == MRI_short)
988 		    ? 1.0/FUNC_scale_short[dset->func_type]
989 		    : (input_thdatum == MRI_byte)
990 		    ? 1.0/FUNC_scale_byte[dset->func_type] : 0.0 ;
991 		}
992 	      break ;
993 
994 	    case MRI_short:
995 	      if( input_datum == MRI_float )
996 		{
997 		  fimfac    = FUNC_scale_short[new_dset->func_type] ;
998 		  fimfacinv = 1.0 / fimfac ;
999 		}
1000 	      else
1001 		if( input_datum == MRI_byte )
1002 		  {
1003 		    fimfac    = ((float)FUNC_scale_short[new_dset->func_type])
1004 		      / FUNC_scale_byte[new_dset->func_type] ;
1005 		    fimfacinv = 1.0 / FUNC_scale_short[new_dset->func_type] ;
1006                   }
1007 		else
1008 		  {
1009 		    fprintf(stderr,
1010 			    "** illegal input_thdatum = %d\n",input_thdatum);
1011                     return("** illegal input_thdatum");
1012 		    /* EXIT(1) ;*/
1013                   }
1014 	      break ;
1015 
1016 	    case MRI_byte:
1017 	      if( input_datum == MRI_float )
1018 		{
1019 		  fimfac    = FUNC_scale_byte[new_dset->func_type] ;
1020 		  fimfacinv = 1.0 / fimfac ;
1021 		}
1022 	      else
1023 		if( input_datum == MRI_short )
1024 		  {
1025 		    fimfac    = ((float)FUNC_scale_byte[new_dset->func_type])
1026 		      / FUNC_scale_short[new_dset->func_type] ;
1027 		    fimfacinv = 1.0 / FUNC_scale_byte[new_dset->func_type] ;
1028                   }
1029 		else
1030 		  {
1031 		    fprintf(stderr,"** illegal input_thdatum = %d\n",
1032 			    input_thdatum);
1033 	            return("** illegal input_thdatum");
1034 	      /* EXIT(1) ;*/
1035                   }
1036 	      break;
1037             }
1038 
1039 	  EDIT_coerce_scale_type( nxyz , fimfac ,
1040 				  DSET_BRICK_TYPE(dset,ival),efim ,
1041 				  output_thdatum,dfim );
1042 
1043 	  DSET_BRICK_FACTOR(new_dset,ii) = fimfacinv;
1044 	  EDIT_substitute_brick( new_dset , ii , output_thdatum , dfim );
1045 	  mri_free( DSET_BRICK(dset,ival) );
1046 	}
1047     }
1048 
1049   if (! PE_be_quiet)
1050     printf("-- Writing edited dataset:%s\n" , DSET_BRIKNAME(new_dset) ) ;
1051 
1052   ival = PLUTO_add_dset( plint , new_dset , DSET_ACTION_MAKE_CURRENT ) ;
1053 
1054   if (ival)
1055     {
1056       THD_delete_3dim_dataset( new_dset , False ) ;
1057       return
1058 	"*********************************************\n"
1059 	"EDIT_main: failure to add new dataset to AFNI\n"
1060 	"*********************************************" ;
1061     }
1062   else
1063     return (NULL) ;
1064 
1065 }
1066 
1067 
1068 
1069 
1070 
1071