/*****************************************************************************
Major portions of this software are copyrighted by the Medical College
of Wisconsin, 1994-2000, and are released under the Gnu General Public
License, Version 2. See the file README.Copyright for details.
******************************************************************************/
static char * g_history[] =
{
"History:",
"",
" 1.0 06 Oct 2005 [rickr] - initial release of 3dmaxima",
" - for now, no improvements over plug_maxima",
" 1.1 18 Aug 2006 [rickr] - added -coords_only option",
};
#define MAXIMA_VERSION "1.1 (August 18, 2005)"
static char * g_help[] =
{
"3dmaxima - used to locate extrema in a functional dataset.",
"",
" This program reads a functional dataset and locates any relative extrema",
" (maximums or minimums, depending on the user option). A _relative_",
" maximum is a point that is greater than all neighbors (not necessarily",
" greater than all other values in the sub-brick). The output from this",
" process can be text based (sent to the terminal window) and it can be a",
" mask (integral) dataset, where the locations of the extrema are set.",
"",
" When writing a dataset, it is often useful to set a sphere around each",
" extrema, not to just set individual voxels. This makes viewing those",
" locations much more reasonable. Also, if the 'Sphere Values' option is",
" set to 'N to 1', the sphere around the most extreme voxel will get the",
" value N, giving it the 'top' color in afni (and so on, down to 1).",
"",
" Notes : The only required option is the input dataset.",
" Input datasets must be of type short.",
" All distances are in voxel units.",
"",
"----------------------------------------------------------------------",
" *** Options ***",
"",
"----- Input Dset: -----",
"",
" -input DSET : specify input dataset",
"",
" e.g. -input func+orig'[7]'",
"",
" Only one sub-brick may be specified. So if a dataset has multiple",
" sub-bricks, the [] selector must be used.",
"",
"----- Output Dset: -----",
"",
" -prefix PREFIX : prefix for an output mask dataset",
"",
" e.g. -prefix maskNto1",
"",
" This dataset may be viewed as a mask. It will have a value set at",
" the location of any selected extrema. The -out_rad option can be",
" used to change those points to 'spheres'.",
"",
" -spheres_1 : [flag] set all output values to 1",
"",
" This is the default, which sets all values in the output dataset",
" to 1. This is for the extreme points, and for the spheres centered",
" around them.",
"",
" -spheres_1toN : [flag] output values will range from 1 to N",
"",
" In this case, the most extreme voxel will be set with a value of 1.",
" The next most extreme voxel will get 2, and so on.",
"",
" -spheres_Nto1 : [flag] output values will range from N to 1",
"",
" With this option, the highest extrema will be set to a value of N,",
" where N equals the number of reported extrema. The advantage of",
" this is that the most extreme point will get the highest color in",
" afni.",
"",
"----- Threshold: -----",
"",
" -thresh CUTOFF : provides a cutoff value for extrema",
"",
" e.g. -thresh 17.4",
"",
" Extrema not meeting this cutoff will not be considered.",
" Note that if the '-neg_ext' option is applied, the user",
" will generally want a negative threshold.",
"",
"----- Separation: -----",
"",
" -min_dist VOXELS : minimum acceptable distance between extrema",
"",
" e.g. -min_dist 4",
"",
" Less significant extrema which are close to more significant extrema",
" will be discounted in some way, depending on the 'neighbor style'",
" options.",
"",
" See '-n_style_sort' and '-n_style_weight_ave' for more information.",
"",
" Note that the distance is in voxels, not mm.",
"",
"----- Output Size: -----",
"",
" -out_rad SIZE : set the output radius around extrema voxels",
"",
" e.g. -out_rad 9",
"",
" If the user wants the output BRIK to consist of 'spheres' centered",
" at extrema points, this option can be used to set the radius for",
" those spheres. Note again that this is in voxel units.",
"",
"----- Neighbor: -----",
"",
" If extrema are not as far apart as is specified by the '-min_dist'",
" option, the neighbor style options specify how to handle the points.",
"",
" -n_style_sort : [flag] use 'Sort-n-Remove' style (default)",
"",
" The extrema are sorted by magnitude. For each extrema (which has",
" not previously removed), all less significant extrema neighbors",
" within the separation radius (-min_dist) are removed.",
"",
" See '-min_dist' for more information.",
"",
" -n_style_weight_ave : [flag] use 'Weighted-Average' style",
"",
" Again, traverse the sorted list of extrema. Replace the current",
" extrema with the center of mass of all extrema within the Separation",
" radius of the current point, removing all others within this radius.",
"",
" This should not change the number of extrema, it should only shift",
" the locations.",
"",
"----- Params: -----",
"",
" -neg_ext : [flag] search for negative extrema (minima)",
"",
" This will search for the minima of the dataset.",
" Note that a negative threshold may be desired.",
"",
" -true_max : [flag] extrema may not have equal neighbors",
"",
" By default, points may be considered extrema even if they have a",
" neighbor with the same value. This flag option requires extrema",
" to be strictly greater than any of their neighbors.",
"",
" With this option, extrema locations that have neighbors at the same",
" value are ignored.",
"",
"----- Output Text: -----",
"",
" -debug LEVEL : output extra information to the terminal",
"",
" e.g. -debug 2",
"",
" -no_text : [flag] do not display the extrma points as text",
"",
" -coords_only : [flag] only output coordinates (no text or vals)",
"",
"----- Output Coords: -----",
"",
" -dset_coords : [flag] display output in the dataset orientation",
"",
" By default, the xyz-coordinates are displayed in DICOM orientation",
" (RAI), i.e. right, anterior and inferior coordinates are negative,",
" and they are printed in that order (RL, then AP, then IS).",
"",
" If this flag is set, the dataset orientation is used, whichever of",
" the 48 it happens to be.",
"",
" Note that in either case, the output orientation is printed above",
" the results in the terminal window, to remind the user.",
"",
"----- Other : -----",
"",
" -help : display this help",
"",
" -hist : display module history",
"",
" -ver : display version number",
"",
"Author: R Reynolds",
""
};
#include "afni.h"
#include "maxima.h"
/*------------------------- option macros -------------------------*/
#define CHECK_NEXT_OPT(n,m,str) \
do { if ( (n) >= (m) ) { \
fprintf(stderr,"** option '%s': missing parameter\n",str); \
fprintf(stderr," consider: '3dmaxima -help'\n"); \
RETURN(1); } \
} while(0)
#define CHECK_NEXT_OPT_MSG(n,m,str,msg) \
do { if ( (n) >= (m) ) { \
fprintf(stderr,"** option '%s': %s\n",str,msg); \
fprintf(stderr," consider: '3dmaxima -help'\n"); \
RETURN(1); } \
} while(0)
/*------------------------ local prototypes -----------------------*/
static int process_args(int argc, char * argv[], r_afni_s * A, maxima_s * M);
/*----------------------------------------------------------------------
**
** Main routine for this plugin (will be called from AFNI).
**
**----------------------------------------------------------------------
*/
int main( int argc, char * argv[] )
{
THD_3dim_dataset * dnew;
r_afni_s A;
maxima_s M;
int rv;
mainENTRY("3dmaxima main"); machdep() ;
if (( rv = process_args( argc, argv, &A, &M )) != 0 )
return(rv > 0);
if ( ! process_data( &M ) )
return 1;
if ( ! M.quiet ) display_coords( &A, &M );
if ( *M.outfile )
{
if ( ( dnew = EDIT_empty_copy( M.dset ) ) == NULL )
{
rERROR( "Error: wr_00\n" "Failed to copy dataset." );
return 1;
}
/* add history */
tross_Copy_History( M.dset , dnew );
tross_Make_History( "3dmaxima", argc, argv, dnew );
if ( ! set_results( &A, &M, dnew ) )
return 1;
DSET_write(dnew);
}
free_memory( &A, &M );
return 0;
}
/*----------------------------------------------------------------------
* process user arguments
*
* return > 0 : valid exit
* 0 : success
* < 0 : failure
*----------------------------------------------------------------------
*/
static int process_args( int argc, char * argv[], r_afni_s * A, maxima_s * M )
{
THD_3dim_dataset * dset = NULL;
char * outfile = NULL;
float cutoff = 0.0, min_dist = 0.0, out_rad = 0.0;
int negatives = 0, quiet = 0, coords_only = 0;
int true_max = 0, opcnt = 0;
int debug = 0, style = MAX_SORT_N_REMOVE_STYLE;
int sval_style = 0, dicom_coords = 1;
int ac;
ENTRY("process_args");
if( argc < 2 )
{
disp_str_list(g_help, sizeof(g_help)/sizeof(char*));
RETURN(1);
}
if( ! init_afni_s( A ) ) RETURN(-1);
for( ac = 1; ac < argc; ac++ )
{
if( ! strcmp( argv[ac], "-input" ) )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-input");
dset = THD_open_dataset(argv[ac]);
if( !dset )
{
fprintf(stderr,"** failed to open dataset '%s'\n",argv[ac]);
RETURN(-1);
}
/* hopefully we can remove this check sometime soon... */
if( DSET_BRICK_TYPE(dset,0) != MRI_short )
{
fprintf(stderr,"** only short datasets are allowed, sorry!\n");
RETURN(-1);
}
if( DSET_NVALS(dset) > 1)
{
fprintf(stderr,"** dset has %d sub-bricks, must indicate one\n",
DSET_NVALS(dset));
RETURN(-1);
}
}
else if( ! strncmp( argv[ac], "-coords_only", 7 ) ) /* 18 Aug 2006 */
{
coords_only = 1;
}
else if( ! strcmp( argv[ac], "-debug" ) )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-debug");
debug = atoi(argv[ac]);
}
else if( ! strcmp( argv[ac], "-dset_coords" ) )
{
dicom_coords = 0;
}
else if( ! strcmp( argv[ac], "-help" ) )
{
disp_str_list(g_help, sizeof(g_help)/sizeof(char*));
RETURN(1);
}
else if( ! strcmp( argv[ac], "-hist" ) )
{
disp_str_list(g_history, sizeof(g_history)/sizeof(char*));
RETURN(1);
}
else if( ! strcmp( argv[ac], "-min_dist" ) )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-min_dist");
min_dist = atof(argv[ac]);
}
else if( ! strcmp( argv[ac], "-out_rad" ) )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-out_rad");
out_rad = atof(argv[ac]);
}
else if( ! strcmp( argv[ac], "-n_style_sort" ) )
{
style = 0;
}
else if( ! strcmp( argv[ac], "-n_style_weight_ave" ) )
{
style = 1;
}
else if( ! strcmp( argv[ac], "-neg_ext" ) )
{
negatives = 1;
}
else if( ! strcmp( argv[ac], "-no_text" ) ) /* no text output */
{
quiet = 1;
}
else if( ! strcmp(argv[ac], "-prefix") )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-prefix");
outfile = argv[ac];
}
else if( ! strcmp( argv[ac], "-spheres_1" ) )
{
sval_style = 0;
}
else if( ! strcmp( argv[ac], "-spheres_1toN" ) )
{
sval_style = 1;
}
else if( ! strcmp( argv[ac], "-spheres_Nto1" ) )
{
sval_style = 2;
}
else if( ! strcmp( argv[ac], "-thresh" ) )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-thresh");
cutoff = atof(argv[ac]);
}
else if( ! strcmp( argv[ac], "-true_max" ) )
{
true_max = 1;
}
else if( ! strcmp( argv[ac], "-ver" ) )
{
puts(MAXIMA_VERSION);
fflush(stdout);
RETURN(1);
}
else /* illegal option? */
{
fprintf(stderr,"** unexpected option: '%s'\n",argv[ac]);
RETURN(-1);
}
opcnt++;
}
if( !dset )
{
fprintf(stderr,"** must specify input dataset via '-input'\n");
RETURN(-1);
}
if( ( out_rad > 0 ) && ( outfile == NULL ) )
{
fprintf(stderr,"** must specify output file to use output radius\n");
RETURN(-1);
}
DSET_load(dset);
if( ! r_set_afni_s_from_dset( A, dset, debug ) )
RETURN(-1);
if( ! init_maxima_s( M, A, outfile ) )
RETURN(-1);
/* now fill any remaining parameters */
M->sval_style = sval_style;
M->cutoff = cutoff / A->factor[0];
M->min_dist = min_dist;
M->out_rad = out_rad;
M->negatives = negatives;
M->ngbr_style = style;
M->quiet = quiet;
M->coords_only = coords_only;
M->true_max = true_max;
M->dicom_coords = dicom_coords;
M->debug = debug;
gr_fac = A->factor[0];
if ( M->debug > 0 )
{
if ( M->debug > 1 ) show_maxima_s( "plugin values applied ", M );
fprintf(stderr," using sub-brick %d, factor %f (1/%f)\n",
A->sub_brick, A->factor[0], 1/A->factor[0]);
}
RETURN(0);
}
syntax highlighted by Code2HTML, v. 0.9.1