Mercurial > hg > minc-tools
changeset 656:301bccc66eb0
Initial revision
author | neelin <neelin> |
---|---|
date | Wed, 02 Nov 1994 16:21:09 +0000 |
parents | 9e605a4a951e |
children | c65d018fc575 |
files | progs/mincreshape/copy_data.c progs/mincreshape/mincreshape.c progs/mincreshape/mincreshape.h progs/mincreshape/mincreshape.man1 |
diffstat | 4 files changed, 2811 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/progs/mincreshape/copy_data.c @@ -0,0 +1,716 @@ +/* ----------------------------- MNI Header ----------------------------------- +@NAME : copy_data +@DESCRIPTION: File containing routines to copy data when reshaping. +@METHOD : +@GLOBALS : +@CREATED : October 25, 1994 (Peter Neelin) +@MODIFIED : $Log: copy_data.c,v $ +@MODIFIED : Revision 1.1 1994-11-02 16:21:09 neelin +@MODIFIED : Initial revision +@MODIFIED : +@COPYRIGHT : + Copyright 1994 Peter Neelin, McConnell Brain Imaging Centre, + Montreal Neurological Institute, McGill University. + Permission to use, copy, modify, and distribute this + software and its documentation for any purpose and without + fee is hereby granted, provided that the above copyright + notice appear in all copies. The author and McGill University + make no representations about the suitability of this + software for any purpose. It is provided "as is" without + express or implied warranty. +---------------------------------------------------------------------------- */ + +#ifndef lint +static char rcsid[]="$Header: /private-cvsroot/minc/progs/mincreshape/copy_data.c,v 1.1 1994-11-02 16:21:09 neelin Exp $"; +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <float.h> +#include <limits.h> +#include <string.h> +#include <math.h> +#include <minc.h> +#include <minc_def.h> +#include "mincreshape.h" + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : copy_data +@INPUT : reshape_info - information for reshaping volume +@OUTPUT : (none) +@RETURNS : (none) +@DESCRIPTION: Copies data from one input volume to another, reorganizing + it according to the reshaping info. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : October 25, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void copy_data(Reshape_info *reshape_info) +{ + int idim, odim, out_ndims; + long block_begin[MAX_VAR_DIMS], block_end[MAX_VAR_DIMS]; + long block_count[MAX_VAR_DIMS]; + long block_cur_start[MAX_VAR_DIMS], block_cur_count[MAX_VAR_DIMS]; + long chunk_begin[MAX_VAR_DIMS], chunk_end[MAX_VAR_DIMS]; + long chunk_count[MAX_VAR_DIMS]; + long chunk_cur_start[MAX_VAR_DIMS], chunk_cur_count[MAX_VAR_DIMS]; + long total_size; + long num_min_values, num_max_values, num_values; + double fillvalue, *minmax_buffer; + void *chunk_data; + + /* Get number of dimensions */ + out_ndims = reshape_info->output_ndims; + + /* Set up variables for looping through blocks */ + for (odim=0; odim < out_ndims; odim++) { + idim = reshape_info->map_out_to_in[odim]; + block_begin[odim] = 0; + block_end[odim] = ABS(reshape_info->input_count[idim]); + if (reshape_info->dim_used_in_block[odim]) + block_count[odim] = ABS(reshape_info->input_count[idim]); + else + block_count[odim] = 1; + } + + /* Figure out size of chunks and allocate space */ + total_size = nctypelen(reshape_info->output_datatype); + for (odim=0; odim < out_ndims; odim++) { + total_size *= reshape_info->chunk_count[odim]; + } + chunk_data = MALLOC(total_size); + + /* Get enough space for image-min and max values for a block */ + get_num_minmax_values(reshape_info, NULL, block_count, + &num_min_values, &num_max_values); + num_values = ((num_min_values > num_max_values) ? + num_min_values : num_max_values); + if (num_values > 0) + minmax_buffer = MALLOC(num_values * sizeof(double)); + else + minmax_buffer = NULL; + + /* Print log message */ + if (reshape_info->verbose) { + (void) fprintf(stderr, "Copying chunks:"); + (void) fflush(stderr); + } + + /* Loop through blocks */ + + nd_begin_looping(block_begin, block_cur_start, out_ndims); + while (!nd_end_of_loop(block_cur_start, block_end, out_ndims)) { + + /* Set up count for current block */ + nd_update_current_count(block_cur_start, block_count, block_end, + block_cur_count, out_ndims); + + /* Set up chunk begin, end and count */ + for (odim=0; odim < out_ndims; odim++) { + chunk_begin[odim] = block_cur_start[odim]; + chunk_end[odim] = chunk_begin[odim] + block_cur_count[odim]; + chunk_count[odim] = reshape_info->chunk_count[odim]; + } + + /* Set up icv for normalization, set output image-max/min and + calculate pixel fill value to use for current block */ + handle_normalization(reshape_info, block_cur_start, block_cur_count, + minmax_buffer, &fillvalue); + + /* Loop through chunks */ + + nd_begin_looping(chunk_begin, chunk_cur_start, out_ndims); + while (!nd_end_of_loop(chunk_cur_start, chunk_end, out_ndims)) { + + /* Set up count for current chunk */ + nd_update_current_count(chunk_cur_start, chunk_count, chunk_end, + chunk_cur_count, out_ndims); + + /* Print log message for chunk */ + if (reshape_info->verbose) { + (void) fprintf(stderr, "."); + (void) fflush(stderr); + } + + /* Copy the chunk */ + copy_the_chunk(reshape_info, + chunk_cur_start, chunk_cur_count, chunk_data, + fillvalue); + + /* Increment chunk loop count */ + nd_increment_loop(chunk_cur_start, chunk_begin, chunk_count, + chunk_end, out_ndims); + + } + + /* Increment block loop count */ + nd_increment_loop(block_cur_start, block_begin, block_count, + block_end, out_ndims); + + } + + /* Free the chunk space */ + FREE(chunk_data); + + /* Print ending log message */ + if (reshape_info->verbose) { + (void) fprintf(stderr, "Done.\n"); + (void) fflush(stderr); + } + + +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : get_num_minmax_values +@INPUT : reshape_info - information for reshaping volume + block_start - start for a block (or NULL) + block_count - count for a block +@OUTPUT : num_min_values - number of image-min values to be read + num_max_values - number of image-max values to be read +@RETURNS : (nothing) +@DESCRIPTION: Gets the number of image-min and image-max values that + correspond to a block. If block_start is NULL, then + it is assumed to translate to an input start of [0,0,...]. + Note that only the true number of values for the specified + block is computed (specifying a hyperslab that goes beyond + file extents does not give a bigger number of values). +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : October 25, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void get_num_minmax_values(Reshape_info *reshape_info, + long *block_start, long *block_count, + long *num_min_values, long *num_max_values) +{ + int iloop, idim, ndims; + int varid, inimgid; + long size; + long minmax_count[MAX_VAR_DIMS]; + long input_block_start[MAX_VAR_DIMS]; + long input_block_count[MAX_VAR_DIMS]; + long *num_values; + + /* Translate output block count to input count */ + translate_output_to_input(reshape_info, block_start, block_count, + input_block_start, input_block_count); + if (block_start != NULL) { + truncate_input_vectors(reshape_info, input_block_start, + input_block_count); + } + inimgid = ncvarid(reshape_info->inmincid, MIimage); + + /* Loop over image-min and image-max */ + + for (iloop=0; iloop < 2; iloop++) { + + /* Get varid and pointer to return value */ + ncopts = 0; + switch (iloop) { + case 0: + varid = ncvarid(reshape_info->inmincid, MIimagemin); + num_values = num_min_values; /* Pointer to long */ + break; + case 1: + varid = ncvarid(reshape_info->inmincid, MIimagemax); + num_values = num_max_values; /* Pointer to long */ + break; + } + ncopts = NCOPTS_DEFAULT; + + /* Translate block count to min or max count and work out the + total number of values. */ + size = 0; + if (varid != MI_ERROR) { + (void) ncvarinq(reshape_info->inmincid, varid, NULL, NULL, + &ndims, NULL, NULL); + (void) mitranslate_coords(reshape_info->inmincid, + inimgid, input_block_count, + varid, minmax_count); + size = 1; + for (idim=0; idim < ndims; idim++) { + size *= minmax_count[idim]; + } + } + *num_values = size; + } + +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : handle_normalization +@INPUT : reshape_info - information for reshaping volume + block_start - start of current block + block_count - count for current block + minmax_buffer - buffer space for getting min and max + values +@OUTPUT : fillvalue - pixel fill value to use for this block +@RETURNS : (none) +@DESCRIPTION: Sets up icv for normalization to ensure that block is + internally normalized. Output image-max and min are set. + The appropriate pixel fill value is calculated for this + min and max (applies to the whole block). +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : October 25, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void handle_normalization(Reshape_info *reshape_info, + long *block_start, + long *block_count, + double *minmax_buffer, + double *fillvalue) +{ + int iloop; + long num_min_values, num_max_values, ivalue; + int inmincid, inimgid, varid, icvid; + long minmax_start[MAX_VAR_DIMS], minmax_count[MAX_VAR_DIMS]; + long input_block_start[MAX_VAR_DIMS], input_block_count[MAX_VAR_DIMS]; + double minimum, maximum, *extreme, valid_min, valid_max, denom; + long num_values; + char *varname; + double sign; + + /* Get input minc id, image id and icv id*/ + inmincid = reshape_info->inmincid; + inimgid = ncvarid(inmincid, MIimage); + icvid = reshape_info->icvid; + + /* Translate output block count to input count */ + translate_output_to_input(reshape_info, block_start, block_count, + input_block_start, input_block_count); + truncate_input_vectors(reshape_info, input_block_start, input_block_count); + + /* Get number of min and max values */ + get_num_minmax_values(reshape_info, block_start, block_count, + &num_min_values, &num_max_values); + + /* Loop over image-min and image-max getting block min and max */ + + for (iloop=0; iloop < 2; iloop++) { + + /* Get varid and pointer to min or max value */ + switch (iloop) { + case 0: + num_values = num_min_values; + varname = MIimagemin; + extreme = &minimum; + sign = -1.0; + break; + case 1: + num_values = num_max_values; + varname = MIimagemax; + extreme = &maximum; + sign = +1.0; + break; + } + + /* Get values from file */ + if (num_values > 0) { + varid = ncvarid(inmincid, varname); + (void) mitranslate_coords(inmincid, + inimgid, input_block_start, + varid, minmax_start); + (void) mitranslate_coords(inmincid, + inimgid, input_block_count, + varid, minmax_count); + (void) mivarget(reshape_info->inmincid, varid, + minmax_start, minmax_count, + NC_DOUBLE, NULL, minmax_buffer); + *extreme = minmax_buffer[0]; + for (ivalue=1; ivalue < num_values; ivalue++) { + if ((minmax_buffer[ivalue] * sign) > (*extreme * sign)) + *extreme = minmax_buffer[ivalue]; + } + } + else { + *extreme = 0.0; + } + if (reshape_info->need_fillvalue && + (reshape_info->fillvalue == NOFILL) && + (0.0 > (*extreme * sign))) + *extreme = 0.0; + + } + + /* Modify the icv if necessary */ + if (reshape_info->do_block_normalization) { + (void) miicv_detach(icvid); + (void) miicv_setdbl(icvid, MI_ICV_IMAGE_MIN, minimum); + (void) miicv_setdbl(icvid, MI_ICV_IMAGE_MAX, maximum); + (void) miicv_setint(icvid, MI_ICV_USER_NORM, TRUE); + (void) miicv_attach(icvid, inmincid, inimgid); + } + + /* Save the image max and min for the block */ + for (iloop=0; iloop < 2; iloop++) { + + /* Get varid and pointer to min or max value */ + switch (iloop) { + case 0: + varname = MIimagemin; + extreme = &minimum; + break; + case 1: + varname = MIimagemax; + extreme = &maximum; + break; + } + + /* Save the value */ + ncopts = 0; + varid = ncvarid(reshape_info->outmincid, varname); + ncopts = NCOPTS_DEFAULT; + if (varid != MI_ERROR) { + (void) mitranslate_coords(reshape_info->outmincid, + reshape_info->outimgid, block_start, + varid, minmax_start); + (void) mivarput1(reshape_info->outmincid, varid, + minmax_start, NC_DOUBLE, NULL, extreme); + } + } + + /* Calculate the pixel fill value */ + *fillvalue = ((reshape_info->fillvalue == NOFILL) ? 0.0 : + reshape_info->fillvalue); + if ((reshape_info->output_datatype != NC_FLOAT) && + (reshape_info->output_datatype != NC_DOUBLE) && + (*fillvalue != FILL)) { + (void) miicv_inqdbl(icvid, MI_ICV_VALID_MIN, &valid_min); + (void) miicv_inqdbl(icvid, MI_ICV_VALID_MAX, &valid_max); + denom = maximum - minimum; + if (denom == 0.0) { + *fillvalue = valid_min; + } + else { + *fillvalue = (*fillvalue - minimum) * + (valid_max - valid_min) / denom + valid_min; + } + } + + +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : truncate_input_vectors +@INPUT : reshape_info - information for reshaping volume + input_start - start of input hyperslab (or NULL) + input_count - count for input hyperslab +@OUTPUT : input_start - start of input hyperslab (or NULL) + input_count - count for input hyperslab +@RETURNS : (nothing) +@DESCRIPTION: Input_start and input_count are truncated to specify a legal hyperslab for + the input file (if not specified, input_start is assumed to be + [0,0,...]). +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : October 25, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void truncate_input_vectors(Reshape_info *reshape_info, + long *input_start, + long *input_count) +{ + int idim; + long first, last; + + /* Check for NULL vectors */ + if (input_count == NULL) return; + + /* Loop through input dimensions */ + for (idim=0; idim < reshape_info->input_ndims; idim++) { + first = ( (input_start != NULL) ? input_start[idim] : 0 ); + last = first + input_count[idim]; + if (first < 0) + input_start[idim] = 0; + else if (first >= reshape_info->input_size[idim]) + input_start[idim] = reshape_info->input_size[idim] - 1; + if (last < 0) + input_count[idim] = 0; + else if (last >= reshape_info->input_size[idim]) + input_count[idim] = reshape_info->input_size[idim] - + input_start[idim]; + } + +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : translate_output_to_input +@INPUT : reshape_info - information for reshaping volume + output_start - start of output hyperslab (or NULL) + output_count - count for output hyperslab +@OUTPUT : input_start - start of input hyperslab (or NULL) + input_count - count for input hyperslab +@RETURNS : (nothing) +@DESCRIPTION: Translates an output start and count to an input start and + count. If output_start or input_start are NULL, then only the + count is translated. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : October 25, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void translate_output_to_input(Reshape_info *reshape_info, + long *output_start, + long *output_count, + long *input_start, + long *input_count) +{ + int idim, odim; + + /* Check for NULL vectors */ + if ((input_count == NULL) || (output_count == NULL)) return; + + /* Loop through input dimensions */ + for (idim=0; idim < reshape_info->input_ndims; idim++) { + odim = reshape_info->map_in_to_out[idim]; + input_count[idim] = ((odim >= 0) ? output_count[odim] : 1); + if ((input_start != NULL) && (output_start != NULL)) { + input_start[idim] = reshape_info->input_start[idim]; + if (odim >= 0) { + if (reshape_info->input_count[idim] > 0) + input_start[idim] += output_start[odim]; + else + input_start[idim] -= + (output_start[odim] + output_count[odim] - 1); + } + } + } + +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : translate_input_to_output +@INPUT : reshape_info - information for reshaping volume + input_start - start of output hyperslab (or NULL) + input_count - count for output hyperslab +@OUTPUT : output_start - start of input hyperslab (or NULL) + output_count - count for input hyperslab +@RETURNS : (nothing) +@DESCRIPTION: Translates an input start and count to an output start and + count. If output_start or input_start are NULL, then only the + count is translated. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : October 25, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void translate_input_to_output(Reshape_info *reshape_info, + long *input_start, + long *input_count, + long *output_start, + long *output_count) +{ + int idim, odim; + + /* Check for NULL vectors */ + if ((input_count == NULL) || (output_count == NULL)) return; + + /* Loop through output dimensions */ + for (odim=0; odim < reshape_info->output_ndims; odim++) { + idim = reshape_info->map_out_to_in[odim]; + output_count[odim] = input_count[idim]; + if ((input_start != NULL) && (output_start != NULL)) { + if (reshape_info->input_count[idim] > 0) + output_start[odim] = input_start[idim] - + reshape_info->input_start[idim]; + else + output_start[odim] = reshape_info->input_start[idim] - + (input_start[idim] + input_count[idim] - 1); + } + } + +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : copy_the_chunk +@INPUT : reshape_info - information for reshaping volume + chunk_start - start of current block + chunk_count - count for current block + chunk_data - pointer to enough space for chunk + fillvalue - pixel value to zero volume, if necessary. +@OUTPUT : (none) +@RETURNS : (nothing) +@DESCRIPTION: Copies the chunk from the input file to the output file. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : October 25, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void copy_the_chunk(Reshape_info *reshape_info, + long chunk_start[], + long chunk_count[], + void *chunk_data, + double fillvalue) +{ + int idim, odim, in_ndims, out_ndims; + long input_start[MAX_VAR_DIMS], input_count[MAX_VAR_DIMS]; + long output_start[MAX_VAR_DIMS], output_count[MAX_VAR_DIMS]; + long input_imap[MAX_VAR_DIMS], output_imap[MAX_VAR_DIMS]; + void *output_origin; + int datatype_size; + long total_size, ipix, first, last; + int zero_data, really_copy_the_data; + union { + char c; short s; long l; float f; double d; + } value_buffer; + + /* Get number of dimensions */ + out_ndims = reshape_info->output_ndims; + in_ndims = reshape_info->input_ndims; + + /* Get size of output datatype */ + datatype_size = nctypelen(reshape_info->output_datatype); + + /* Create input start and count */ + translate_output_to_input(reshape_info, chunk_start, chunk_count, + input_start, input_count); + + /* Find out if we need to zero the volume and if we need to copy any + data */ + zero_data = FALSE; + really_copy_the_data = TRUE; + total_size = 1; + for (idim=0; idim < in_ndims; idim++) { + first = input_start[idim]; + last = input_start[idim] + input_count[idim] - 1; + if ((first < 0) || (last >= reshape_info->input_size[idim])) + zero_data = TRUE; + if ((last < 0) || (first >= reshape_info->input_size[idim])) + really_copy_the_data = FALSE; + total_size *= input_count[idim]; + } + + /* Make sure that input vectors are legal and translate them back + to output */ + truncate_input_vectors(reshape_info, input_start, input_count); + translate_input_to_output(reshape_info, input_start, input_count, + output_start, output_count); + + /* Write out zero data if needed */ + if (zero_data) { + convert_value_from_double(fillvalue, + reshape_info->output_datatype, + reshape_info->output_is_signed, + &value_buffer); + for (ipix=0; ipix < total_size; ipix++) { + (void) memcpy((char *)chunk_data + ipix*datatype_size, + &value_buffer, datatype_size); + } + (void) ncvarput(reshape_info->outmincid, reshape_info->outimgid, + chunk_start, chunk_count, chunk_data); + } + + /* Set up hypothetical imap variable for input */ + for (idim=in_ndims-1; idim >= 0; idim--) { + input_imap[idim] = ((idim == in_ndims-1) ? + datatype_size : + input_imap[idim+1] * input_count[idim+1]); + } + + /* Create output imap variable from input one (re-ordering dimensions and + flipping). Also work out the chunk origin (point to byte for output + [0,0,0...]). */ + output_origin = chunk_data; + for (odim=0; odim < out_ndims; odim++) { + idim = reshape_info->map_out_to_in[odim]; + if (reshape_info->input_count[idim] > 0) { + output_imap[odim] = input_imap[idim]; + } + else { + output_imap[odim] = -input_imap[idim]; + output_origin = + (void *) ((char *)output_origin - + (output_count[odim] - 1) * output_imap[odim]); + } + } + + /* Should we really copy the data? */ + if (really_copy_the_data) { + + /* Read in the data */ + (void) miicv_get(reshape_info->icvid, input_start, input_count, + chunk_data); + + /* Write it out */ + (void) ncvarputg(reshape_info->outmincid, reshape_info->outimgid, + output_start, output_count, NULL, output_imap, + output_origin); + + } + +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : convert_value_from_double +@INPUT : dvalue - double value to convert + datatype - type of desired value + is_signed - TRUE if desired value is signed +@OUTPUT : ptr - pointer to converted value +@RETURNS : (nothing) +@DESCRIPTION: Converts a value from double to some other value. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : October 25, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void convert_value_from_double(double dvalue, + nc_type datatype, int is_signed, + void *ptr) +{ + switch (datatype) { + case NC_BYTE : + if (!is_signed) { + dvalue = MAX(0, dvalue); + dvalue = MIN(UCHAR_MAX, dvalue); + *((unsigned char *) ptr) = ROUND(dvalue); + } + else { + dvalue = MAX(SCHAR_MIN, dvalue); + dvalue = MIN(SCHAR_MAX, dvalue); + *((signed char *) ptr) = ROUND(dvalue); + } + break; + case NC_SHORT : + if (!is_signed) { + dvalue = MAX(0, dvalue); + dvalue = MIN(USHRT_MAX, dvalue); + *((unsigned short *) ptr) = ROUND(dvalue); + } + else { + dvalue = MAX(SHRT_MIN, dvalue); + dvalue = MIN(SHRT_MAX, dvalue); + *((signed short *) ptr) = ROUND(dvalue); + } + break; + case NC_LONG : + if (!is_signed) { + dvalue = MAX(0, dvalue); + dvalue = MIN(ULONG_MAX, dvalue); + *((unsigned long *) ptr) = ROUND(dvalue); + } + else { + dvalue = MAX(LONG_MIN, dvalue); + dvalue = MIN(LONG_MAX, dvalue); + *((signed long *) ptr) = ROUND(dvalue); + } + break; + case NC_FLOAT : + dvalue = MAX(-FLT_MAX,dvalue); + *((float *) ptr) = MIN(FLT_MAX,dvalue); + break; + case NC_DOUBLE : + *((double *) ptr) = dvalue; + break; + } +}
new file mode 100644 --- /dev/null +++ b/progs/mincreshape/mincreshape.c @@ -0,0 +1,1598 @@ +/* ----------------------------- MNI Header ----------------------------------- +@NAME : mincreshape +@INPUT : argc, argv - command line arguments +@OUTPUT : (none) +@RETURNS : error status +@DESCRIPTION: Program to allow reshaping of minc lattices: selecting a + a subrange (or superrange) of dimension indices, eliminating + dimensions, or re-ordering axes. As well, all icv conversions + are made accessible on the command line. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : March 10, 1994 (Peter Neelin) +@MODIFIED : $Log: mincreshape.c,v $ +@MODIFIED : Revision 1.1 1994-11-02 16:21:24 neelin +@MODIFIED : Initial revision +@MODIFIED : +@COPYRIGHT : + Copyright 1993 Peter Neelin, McConnell Brain Imaging Centre, + Montreal Neurological Institute, McGill University. + Permission to use, copy, modify, and distribute this + software and its documentation for any purpose and without + fee is hereby granted, provided that the above copyright + notice appear in all copies. The author and McGill University + make no representations about the suitability of this + software for any purpose. It is provided "as is" without + express or implied warranty. +---------------------------------------------------------------------------- */ + +#ifndef lint +static char rcsid[]="$Header: /private-cvsroot/minc/progs/mincreshape/mincreshape.c,v 1.1 1994-11-02 16:21:24 neelin Exp $"; +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <float.h> +#include <limits.h> +#include <string.h> +#include <math.h> +#include <minc.h> +#include <ParseArgv.h> +#include <time_stamp.h> +#include <minc_def.h> +#include "mincreshape.h" + +/* Main program */ + +public int main(int argc, char *argv[]) +{ + Reshape_info reshape_info; + + /* Get argument information and create the output file */ + get_arginfo(argc, argv, &reshape_info); + + /* Copy the data */ + copy_data(&reshape_info); + + /* Close the output file */ + (void) miattputstr(reshape_info.outmincid, reshape_info.outimgid, + MIcomplete, MI_TRUE); + (void) miclose(reshape_info.outmincid); + + exit(EXIT_SUCCESS); +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : get_arginfo +@INPUT : argc - number of command-line arguments + argv - command-line arguments +@OUTPUT : reshape_info - information for reshaping file +@RETURNS : (nothing) +@DESCRIPTION: Routine to get information from arguments about input and + output files and reshaping. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : March 11, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void get_arginfo(int argc, char *argv[], + Reshape_info *reshape_info) +{ + + /* Argument variables */ + static int clobber = FALSE; + static int verbose = TRUE; + static nc_type datatype = NC_UNSPECIFIED; + static int is_signed = INT_MIN; + static double valid_range[2] = {DBL_MAX,DBL_MAX}; + static double image_range[2] = {DBL_MAX,DBL_MAX}; + static int do_norm = FALSE; + static double pixfillvalue = FILL; + static int do_scalar= FALSE; + static int direction = MI_ICV_ANYDIR; + static int xdirection = INT_MIN; + static int ydirection = INT_MIN; + static int zdirection = INT_MIN; + static int keep_aspect = FALSE; + static int image_size = MI_ICV_ANYSIZE; + static int row_size = MI_ICV_ANYSIZE; + static int col_size = MI_ICV_ANYSIZE; + static Dimsize_list dimsize_list = {0}; + static char *axis_order[MAX_VAR_DIMS+1]; + static Axis_ranges axis_ranges = {0}; + static long hs_start[MAX_VAR_DIMS] = {LONG_MIN}; + static long hs_count[MAX_VAR_DIMS] = {LONG_MIN}; + static double fillvalue = NOFILL; + static int max_chunk_size_in_kb = DEFAULT_MAX_CHUNK_SIZE_IN_KB; + + /* Argument table */ + static ArgvInfo argTable[] = { + {NULL, ARGV_HELP, (char *) NULL, (char *) NULL, + "General options:"}, + {"-clobber", ARGV_CONSTANT, (char *) TRUE, (char *) &clobber, + "Overwrite existing file."}, + {"-noclobber", ARGV_CONSTANT, (char *) FALSE, (char *) &clobber, + "Do not overwrite existing file (default)."}, + {"-verbose", ARGV_CONSTANT, (char *) TRUE, (char *) &verbose, + "Print out log messages as processing is being done (default).\n"}, + {"-quiet", ARGV_CONSTANT, (char *) FALSE, (char *) &verbose, + "Do not print out any log messages."}, + {"-max_chunk_size_in_kb", ARGV_INT, (char *) 0, + (char *) &max_chunk_size_in_kb, + "Specify the maximum size of the copy buffer (in kbytes)."}, + + {NULL, ARGV_HELP, (char *) NULL, (char *) NULL, + "Image conversion options (pixel type and range):"}, + {"-filetype", ARGV_CONSTANT, (char *) NC_UNSPECIFIED, (char *) &datatype, + "Don't do any type conversion (default)."}, + {"-byte", ARGV_CONSTANT, (char *) NC_BYTE, (char *) &datatype, + "Convert to byte data"}, + {"-short", ARGV_CONSTANT, (char *) NC_SHORT, (char *) &datatype, + "Convert to short integer data"}, + {"-long", ARGV_CONSTANT, (char *) NC_LONG, (char *) &datatype, + "Convert to long integer data"}, + {"-float", ARGV_CONSTANT, (char *) NC_FLOAT, (char *) &datatype, + "Convert to single-precision floating-point data"}, + {"-double", ARGV_CONSTANT, (char *) NC_DOUBLE, (char *) &datatype, + "Convert to double-precision floating-point data"}, + {"-signed", ARGV_CONSTANT, (char *) TRUE, (char *) &is_signed, + "Convert to signed integer data"}, + {"-unsigned", ARGV_CONSTANT, (char *) FALSE, (char *) &is_signed, + "Convert to unsigned integer data"}, + {"-valid_range", ARGV_FLOAT, (char *) 2, (char *) valid_range, + "Valid range for output data (pixel values)"}, + + {"-image_range", ARGV_FLOAT, (char *) 2, (char *) image_range, + "Normalize images to a given minimum and maximum"}, + {"-normalize", ARGV_CONSTANT, (char *) TRUE, (char *) &do_norm, + "Normalize images to file minimum and maximum."}, + {"-nonormalize", ARGV_CONSTANT, (char *) FALSE, (char *) &do_norm, + "Do not normalize images (default)."}, + {"-nopixfill", ARGV_FUNC, (char *) get_fillvalue, + (char *) &pixfillvalue, + "Do not convert out-of-range values in input file."}, + {"-pixfill", ARGV_FUNC, (char *) get_fillvalue, + (char *) &pixfillvalue, + "Replace out-of-range values in input file by smallest value (default)."}, + {"-pixfillvalue", ARGV_FLOAT, (char *) 0, + (char *) &pixfillvalue, + "Specify new value to replace out-of-range values in input file."}, + + {NULL, ARGV_HELP, (char *) NULL, (char *) NULL, + "Image conversion options (dimension direction and size):"}, + {"-scalar", ARGV_CONSTANT, (char *) TRUE, (char *) &do_scalar, + "Convert vector images to scalar images."}, + {"-noscalar", ARGV_CONSTANT, (char *) FALSE, (char *) &do_scalar, + "Do not convert vector images to scalar images (default)."}, + + {"+direction", ARGV_CONSTANT, (char *) MI_ICV_POSITIVE, + (char *) &direction, + "Flip images to give positive step value for spatial axes."}, + {"-direction", ARGV_CONSTANT, (char *) MI_ICV_NEGATIVE, + (char *) &direction, + "Flip images to give negative step value for spatial axes."}, + {"-anydirection", ARGV_CONSTANT, (char *) MI_ICV_ANYDIR, + (char *) &direction, + "Don't flip images along spatial axes (default)."}, + {"+xdirection", ARGV_CONSTANT, (char *) MI_ICV_POSITIVE, + (char *) &xdirection, + "Flip images to give positive xspace:step value (left-to-right)."}, + {"-xdirection", ARGV_CONSTANT, (char *) MI_ICV_NEGATIVE, + (char *) &xdirection, + "Flip images to give negative xspace:step value (right-to-left)."}, + {"-xanydirection", ARGV_CONSTANT, (char *) MI_ICV_ANYDIR, + (char *) &xdirection, + "Don't flip images along x-axis."}, + {"+ydirection", ARGV_CONSTANT, (char *) MI_ICV_POSITIVE, + (char *) &ydirection, + "Flip images to give positive yspace:step value (post-to-ant)."}, + {"-ydirection", ARGV_CONSTANT, (char *) MI_ICV_NEGATIVE, + (char *) &ydirection, + "Flip images to give negative yspace:step value (ant-to-post)."}, + {"-yanydirection", ARGV_CONSTANT, (char *) MI_ICV_ANYDIR, + (char *) &ydirection, + "Don't flip images along y-axis."}, + {"+zdirection", ARGV_CONSTANT, (char *) MI_ICV_POSITIVE, + (char *) &zdirection, + "Flip images to give positive zspace:step value (inf-to-sup)."}, + {"-zdirection", ARGV_CONSTANT, (char *) MI_ICV_NEGATIVE, + (char *) &zdirection, + "Flip images to give negative zspace:step value (sup-to-inf)."}, + {"-zanydirection", ARGV_CONSTANT, (char *) MI_ICV_ANYDIR, + (char *) &zdirection, + "Don't flip images along z-axis."}, + + {"-keepaspect", ARGV_CONSTANT, (char *) TRUE, (char *) &keep_aspect, + "Preserve aspect ratio when resizing images."}, + {"-nokeepaspect", ARGV_CONSTANT, (char *) FALSE, (char *) &keep_aspect, + "Do not preserve aspect ratio when resizing images (default)."}, + + {"-imgsize", ARGV_INT, (char *) 0, (char *) &image_size, + "Specify the desired image size."}, + {"-rowsize", ARGV_INT, (char *) 0, (char *) &row_size, + "Specify the desired number of rows in the image."}, + {"-colsize", ARGV_INT, (char *) 0, (char *) &col_size, + "Specify the desired number of columns in the image."}, + {"-dimsize", ARGV_FUNC, (char *) get_dimsize, + (char *) &dimsize_list, + "Specify the size of a named dimension (<dimension>=<size>)."}, + + {NULL, ARGV_HELP, (char *) NULL, (char *) NULL, + "Reshaping options:"}, + {"-transverse", ARGV_FUNC, (char *) get_axis_order, + (char *) axis_order, + "Write out transverse slices"}, + {"-sagittal", ARGV_FUNC, (char *) get_axis_order, + (char *) axis_order, + "Write out sagittal slices"}, + {"-coronal", ARGV_FUNC, (char *) get_axis_order, + (char *) axis_order, + "Write out coronal slices"}, + {"-dimorder", ARGV_FUNC, (char *) get_axis_order, + (char *) axis_order, + "Specify dimension order (<dim1>,<dim2>,<dim3>,...)."}, + {"-dimrange", ARGV_FUNC, (char *) get_axis_range, + (char *) &axis_ranges, + "Specify range of dimension subscripts (<dim>=<start>[,<count>])."}, + {"-start", ARGV_FUNC, (char *) get_arg_vector, (char *) hs_start, + "Specifies corner of hyperslab (C conventions for indices)"}, + {"-count", ARGV_FUNC, (char *) get_arg_vector, (char *) hs_count, + "Specifies edge lengths of hyperslab to read"}, + + {NULL, ARGV_HELP, (char *) NULL, (char *) NULL, + "Missing data options:"}, + {"-nofill", ARGV_FUNC, (char *) get_fillvalue, + (char *) &fillvalue, + "Use value zero for points outside of input volume (default)"}, + {"-fill", ARGV_FUNC, (char *) get_fillvalue, + (char *) &fillvalue, + "Use a fill value for points outside of input volume"}, + {"-fillvalue", ARGV_FLOAT, (char *) 0, + (char *) &fillvalue, + "Specify a fill value for points outside of input volume"}, + + {NULL, ARGV_END, NULL, NULL, NULL} + }; + + /* Other variables */ + char *infile, *outfile; + char *history, *pname; + int icvid; + + /* Get the history information and program name */ + history = time_stamp(argc, argv); + pname = argv[0]; + + /* Call ParseArgv */ + if (ParseArgv(&argc, argv, argTable, 0) || (argc!=3)) { + (void) fprintf(stderr, + "\nUsage: %s [<options>] <infile> <outfile>\n", pname); + (void) fprintf(stderr, + " %s [-help]\n\n", pname); + exit(EXIT_FAILURE); + } + infile = argv[1]; + outfile = argv[2]; + + /* Save verbose setting */ + reshape_info->verbose = verbose; + + /* Check the x, y and z directions */ + if (xdirection == INT_MIN) xdirection = direction; + if (ydirection == INT_MIN) ydirection = direction; + if (zdirection == INT_MIN) zdirection = direction; + + /* Check the row and column size */ + if (row_size == MI_ICV_ANYSIZE) row_size = image_size; + if (col_size == MI_ICV_ANYSIZE) col_size = image_size; + + /* Check for normalization to specified range */ + if (image_range[0] != DBL_MAX) do_norm = TRUE; + + /* Open the input file */ + reshape_info->inmincid = miopen(infile, NC_NOWRITE); + + /* Get the default datatype */ + get_default_datatype(reshape_info->inmincid, &datatype, &is_signed, + valid_range); + reshape_info->output_datatype = datatype; + reshape_info->output_is_signed = is_signed; + + /* Create the icv */ + reshape_info->icvid = miicv_create(); + icvid = reshape_info->icvid; + + /* Set the icv properties */ + + /* Set datatype properties (get min and max for type from icv) */ + (void) miicv_setint(icvid, MI_ICV_TYPE, datatype); + if (is_signed != INT_MIN) { + if (is_signed) + (void) miicv_setstr(icvid, MI_ICV_SIGN, MI_SIGNED); + else + (void) miicv_setstr(icvid, MI_ICV_SIGN, MI_UNSIGNED); + } + if (valid_range[0] != DBL_MAX) { + (void) miicv_setdbl(icvid, MI_ICV_VALID_MIN, valid_range[0]); + (void) miicv_setdbl(icvid, MI_ICV_VALID_MAX, valid_range[1]); + } + + /* Check for normalization */ + (void) miicv_setint(icvid, MI_ICV_DO_NORM, do_norm); + (void) miicv_setint(icvid, MI_ICV_USER_NORM, (image_range[0] != DBL_MAX)); + (void) miicv_setdbl(icvid, MI_ICV_IMAGE_MIN, image_range[0]); + (void) miicv_setdbl(icvid, MI_ICV_IMAGE_MAX, image_range[1]); + + /* Check for pixel fill value conversion */ + (void) miicv_setint(icvid, MI_ICV_DO_FILLVALUE, + (pixfillvalue != NOFILL)); + (void) miicv_setdbl(icvid, MI_ICV_FILLVALUE, pixfillvalue); + + /* Set up for dimension conversion */ + (void) miicv_setint(icvid, MI_ICV_DO_DIM_CONV, TRUE); + (void) miicv_setint(icvid, MI_ICV_DO_SCALAR, do_scalar); + (void) miicv_setint(icvid, MI_ICV_XDIM_DIR, xdirection); + (void) miicv_setint(icvid, MI_ICV_YDIM_DIR, ydirection); + (void) miicv_setint(icvid, MI_ICV_ZDIM_DIR, zdirection); + + /* Set up for image resizing */ + (void) miicv_setint(icvid, MI_ICV_KEEP_ASPECT, keep_aspect); + (void) miicv_setint(icvid, MI_ICV_ADIM_SIZE, col_size); + (void) miicv_setint(icvid, MI_ICV_BDIM_SIZE, row_size); + setup_dim_sizes(icvid, reshape_info->inmincid, &dimsize_list); + + /* Save reshaping information */ + setup_reshaping_info(icvid, reshape_info->inmincid, + do_norm, fillvalue, do_scalar, + axis_order, &axis_ranges, hs_start, hs_count, + max_chunk_size_in_kb, + reshape_info); + + /* Attach the icv */ + (void) miicv_attach(icvid, reshape_info->inmincid, + ncvarid(reshape_info->inmincid, MIimage)); + + /* Create the output file */ + reshape_info->outmincid = + micreate(outfile, (clobber ? NC_CLOBBER : NC_NOCLOBBER)); + setup_output_file(reshape_info->outmincid, history, reshape_info); + + return; +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : get_fillvalue +@INPUT : dst - Pointer to client data from argument table + key - argument key + nextArg - argument following key +@OUTPUT : (nothing) +@RETURNS : FALSE so that ParseArgv will not discard nextArg +@DESCRIPTION: Routine called by ParseArgv to set the fill value +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : March 16, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public int get_fillvalue(char *dst, char *key, char *nextArg) +{ /* ARGSUSED */ + double *dptr; + + /* Get pointer to client data */ + dptr = (double *) dst; + + /* Check key for fill value to set */ + if ((strcmp(key, "-fill") == 0) || + (strcmp(key, "-pixfill") == 0)) { + *dptr = FILL; + } + else if ((strcmp(key, "-nofill") == 0) || + (strcmp(key, "-nopixfill") == 0)) { + *dptr = NOFILL; + } + + return FALSE; +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : get_dimsize +@INPUT : dst - Pointer to client data from argument table + key - argument key + nextArg - argument following key +@OUTPUT : (nothing) +@RETURNS : TRUE so that ParseArgv will discard nextArg +@DESCRIPTION: Routine called by ParseArgv to get a dimension size +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : March 16, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public int get_dimsize(char *dst, char *key, char *nextArg) +{ /* ARGSUSED */ + Dimsize_list *dimsize_list; + char *size_string; + int ientry; + char *cur; + + /* Get pointer to client data */ + dimsize_list = (Dimsize_list *) dst; + + /* Check for next argument */ + if (nextArg == NULL) { + (void) fprintf(stderr, + "\"%s\" option requires an additional argument\n", + key); + exit(EXIT_FAILURE); + } + + /* Check that we have enough space in the list */ + if (dimsize_list->nentries >= MAX_VAR_DIMS) { + (void) fprintf(stderr, "Too many \"%s\" options.\n", key); + exit(EXIT_FAILURE); + } + ientry = dimsize_list->nentries; + + /* Parse the argument (<dim name>=<size>) */ + + /* Remove leading space */ + while (ISSPACE(*nextArg)) nextArg++; + dimsize_list->name[ientry] = nextArg; + + /* Find the '=' */ + size_string = strchr(nextArg, '='); + if ((size_string == NULL) || (size_string == nextArg)) { + (void) fprintf(stderr, + "\"%s\" option requires the argument <dim>=<size>\n", + key); + exit(EXIT_FAILURE); + } + + /* Remove trailing blanks on name */ + cur = size_string - 1; + while ((cur>=nextArg) && ISSPACE(*cur)) cur--; + cur++; + *cur = '\0'; + + /* Get the size */ + size_string++; + dimsize_list->size[ientry] = strtol(size_string, &cur, 0); + if (cur == size_string) { + (void) fprintf(stderr, + "\"%s\" option requires the argument <dim>=<size>\n", + key); + exit(EXIT_FAILURE); + } + + dimsize_list->nentries++; + + return TRUE; +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : get_axis_order +@INPUT : dst - Pointer to client data from argument table + key - argument key + nextArg - argument following key +@OUTPUT : (nothing) +@RETURNS : TRUE or FALSE (so that ParseArgv will discard nextArg only + when needed) +@DESCRIPTION: Routine called by ParseArgv to set the axis order +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : March 16, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public int get_axis_order(char *dst, char *key, char *nextArg) +{ /* ARGSUSED */ + char **axis_order; + char *cur; + int ndims; + + /* Get pointer to client data */ + axis_order = (char **) dst; + + /* Check key */ + if (strcmp(key, "-transverse") == 0) { + axis_order[0] = MIzspace; + axis_order[1] = MIyspace; + axis_order[2] = MIxspace; + return FALSE; + } + if (strcmp(key, "-sagittal") == 0) { + axis_order[0] = MIxspace; + axis_order[1] = MIzspace; + axis_order[2] = MIyspace; + return FALSE; + } + if (strcmp(key, "-coronal") == 0) { + axis_order[0] = MIyspace; + axis_order[1] = MIzspace; + axis_order[2] = MIxspace; + return FALSE; + } + + /* Make sure that we have a "-dimorder" argument */ + if (strcmp(key, "-dimorder") != 0) { + (void) fprintf(stderr, + "Unrecognized option \"%s\": internal program error.\n", + key); + exit(EXIT_FAILURE); + } + + /* Check for next argument */ + if (nextArg == NULL) { + (void) fprintf(stderr, + "\"%s\" option requires an additional argument\n", + key); + exit(EXIT_FAILURE); + } + + /* Set up pointers to end of string and first non-space character */ + cur = nextArg; + while (ISSPACE(*cur)) cur++; + ndims = 0; + + /* Loop through string looking for space or comma-separated names */ + while ((ndims < MAX_VAR_DIMS) && (*cur!='\0')) { + + /* Get string */ + axis_order[ndims] = cur; + + /* Search for end of dimension name */ + while (!ISSPACE(*cur) && (*cur != ',') && (*cur != '\0')) cur++; + if (*cur != '\0') { + *cur = '\0'; + cur++; + } + ndims++; + + /* Skip any spaces */ + while (ISSPACE(*cur)) cur++; + + } + + /* Terminate list with NULL */ + axis_order[ndims] = NULL; + + return TRUE; +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : get_axis_range +@INPUT : dst - Pointer to client data from argument table + key - argument key + nextArg - argument following key +@OUTPUT : (nothing) +@RETURNS : TRUE so that ParseArgv will discard nextArg +@DESCRIPTION: Routine called by ParseArgv to set the axis range +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : March 16, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public int get_axis_range(char *dst, char *key, char *nextArg) +{ /* ARGSUSED */ + Axis_ranges *axis_ranges; + int ientry; + char *num_string, *cur; + + /* Get pointer to client data */ + axis_ranges = (Axis_ranges *) dst; + + /* Check for next argument */ + if (nextArg == NULL) { + (void) fprintf(stderr, + "\"%s\" option requires an additional argument\n", + key); + exit(EXIT_FAILURE); + } + + /* Check that we have enough space in the list */ + if (axis_ranges->nentries >= MAX_VAR_DIMS) { + (void) fprintf(stderr, "Too many \"%s\" options.\n", key); + exit(EXIT_FAILURE); + } + ientry = axis_ranges->nentries; + + /* Parse the argument (<dim name>=<start>,[<count>]) */ + + /* Remove leading space */ + while (ISSPACE(*nextArg)) nextArg++; + axis_ranges->name[ientry] = nextArg; + + /* Find the '=' */ + num_string = strchr(nextArg, '='); + if ((num_string == NULL) || (num_string == nextArg)) { + (void) fprintf(stderr, + "\"%s\" option requires the argument <dim>=<start>[,<count>]\n", + key); + exit(EXIT_FAILURE); + } + + /* Remove trailing blanks on name */ + cur = num_string - 1; + while ((cur>=nextArg) && ISSPACE(*cur)) cur--; + cur++; + *cur = '\0'; + + /* Get the start */ + num_string++; + axis_ranges->start[ientry] = strtol(num_string, &cur, 0); + if (cur == num_string) { + (void) fprintf(stderr, + "\"%s\" option requires the argument <dim>=<start>[,<count>]\n", + key); + exit(EXIT_FAILURE); + } + + /* Skip any spaces */ + while (ISSPACE(*cur)) cur++; + + /* Skip an optional comma */ + if (*cur == ',') cur++; + + /* Look for a count string */ + num_string = cur; + axis_ranges->count[ientry] = strtol(num_string, &cur, 0); + if ((cur == num_string) || (axis_ranges->count[ientry] == 0)) { + axis_ranges->count[ientry] = 0; + } + + axis_ranges->nentries++; + + return TRUE; +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : get_arg_vector +@INPUT : key - argv key string (-start, -count) + nextArg - string from which vector should be read +@OUTPUT : dst - pointer to vector of longs into which values should + be written (padded with LONG_MIN) +@RETURNS : TRUE, since nextArg is used (unless it is NULL) +@DESCRIPTION: Parses a command-line argument into a vector of longs. The + string should contain at most MAX_VAR_DIMS comma separated + integer values (spaces are skipped). +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : June 10, 1993 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public int get_arg_vector(char *dst, char *key, char *nextArg) +{ /* ARGSUSED */ + + long *vector; + int nvals, i; + char *cur, *end, *prev; + + /* Check for following argument */ + if (nextArg == NULL) { + (void) fprintf(stderr, + "\"%s\" option requires an additional argument\n", + key); + return FALSE; + } + + /* Get pointer to vector of longs */ + vector = (long *) dst; + + /* Set up pointers to end of string and first non-space character */ + end = nextArg + strlen(nextArg); + cur = nextArg; + while (ISSPACE(*cur)) cur++; + nvals = 0; + + /* Loop through string looking for integers */ + while ((nvals < MAX_VAR_DIMS) && (cur!=end)) { + + /* Get integer */ + prev = cur; + vector[nvals] = strtol(prev, &cur, 0); + if (cur == prev) { + (void) fprintf(stderr, + "expected vector of integers for \"%s\", but got \"%s\"\n", + key, nextArg); + exit(EXIT_FAILURE); + } + nvals++; + + /* Skip any spaces */ + while (ISSPACE(*cur)) cur++; + + /* Skip an optional comma */ + if (*cur == VECTOR_SEPARATOR) cur++; + + } + + /* Pad with LONG_MIN */ + for (i=nvals; i < MAX_VAR_DIMS; i++) { + vector[i] = LONG_MIN; + } + + return TRUE; +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : get_default_datatype +@INPUT : mincid - id of input minc file +@OUTPUT : datatype - datatype of file + is_signed - TRUE if data is signed, FALSE if not. Defaults + to FALSE for byte, TRUE otherwise. + valid_range - DBL_MAX if not known +@RETURNS : (nothing) +@DESCRIPTION: Routine to get the datatype info from a file. If datatype + is not NC_UNSPECIFIED, then is_signed only is set to its + default. Otherwise, is_signed is only modified if it is set + to INT_MIN and valid_range is only modified if it is set to + DBL_MAX. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : March 16, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void get_default_datatype(int mincid, nc_type *datatype, int *is_signed, + double valid_range[2]) +{ + int imgid; + int status; + double vrange[2]; + char string[MI_MAX_ATTSTR_LEN]; + int length; + + /* Get the image variable id */ + imgid = ncvarid(mincid, MIimage); + + /* Check that datatype is not specified */ + if (*datatype != NC_UNSPECIFIED) { + if (*is_signed == INT_MIN) { + *is_signed = ((*datatype == NC_BYTE) ? FALSE : TRUE); + } + return; + } + + /* Get data type */ + (void) ncvarinq(mincid, imgid, NULL, datatype, NULL, NULL, NULL); + + /* Look for sign if needed */ + if (*is_signed == INT_MIN) { + ncopts = 0; + if (miattgetstr(mincid, imgid, MIsigntype, sizeof(string), string) + != NULL) { + if (strcmp(string, MI_SIGNED) == 0) + *is_signed = TRUE; + else if (strcmp(string, MI_UNSIGNED) == 0) + *is_signed = FALSE; + } + ncopts = NCOPTS_DEFAULT; + if (*is_signed == INT_MIN) { + *is_signed = ((*datatype == NC_BYTE) ? FALSE : TRUE); + } + } + + /* Look for valid range if needed */ + if (valid_range[0] == DBL_MAX) { + ncopts = 0; + status=miattget(mincid, imgid, MIvalid_range, + NC_DOUBLE, 2, vrange, &length); + if ((status!=MI_ERROR) && (length==2)) { + if (vrange[1] > vrange[0]) { + valid_range[0] = vrange[0]; + valid_range[1] = vrange[1]; + } + else { + valid_range[0] = vrange[1]; + valid_range[1] = vrange[0]; + } + } + else { + status=miattget1(mincid, imgid, MIvalid_max, + NC_DOUBLE, &vrange[1]); + if (status!=MI_ERROR) valid_range[1] = vrange[1]; + + status=miattget1(mincid, imgid, MIvalid_min, + NC_DOUBLE, &vrange[0]); + if (status!=MI_ERROR) + if (status!=MI_ERROR) valid_range[1] = vrange[1]; + + } + ncopts = NCOPTS_DEFAULT; + } + + return; +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : setup_dim_sizes +@INPUT : mincid - id of input minc file + dimsize_list - list of dimension names and sizes +@OUTPUT : icvid - icvid to modify +@RETURNS : (nothing) +@DESCRIPTION: Routine to modify an icv so that the appropriate dimensions + have given sizes +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : May 18, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void setup_dim_sizes(int icvid, int mincid, Dimsize_list *dimsize_list) +{ + int ientry, idim; + int imgid, dimid; + int ndims; + int dim[MAX_VAR_DIMS]; + char dimname[MAX_NC_NAME]; + int image_dim, n_image_dims; + + /* Get image dimension info */ + imgid = ncvarid(mincid, MIimage); + (void) ncvarinq(mincid, imgid, NULL, NULL, &ndims, dim, NULL); + if (ndims > 0) { + (void) ncdiminq(mincid, dim[ndims-1], dimname, NULL); + if (strcmp(dimname, MIvector_dimension) == 0) ndims--; + } + + /* Get default number of image dimensions */ + (void) miicv_inqint(icvid, MI_ICV_NUM_IMGDIMS, &n_image_dims); + + /* Loop through list of names, looking for dimensions */ + for (ientry=0; ientry < dimsize_list->nentries; ientry++) { + ncopts = 0; + dimid = ncdimid(mincid, dimsize_list->name[ientry]); + ncopts = NCOPTS_DEFAULT; + for (idim=0; idim < ndims; idim++) { + if (dim[idim] == dimid) break; + } + if (idim < ndims) { + image_dim = ndims - idim - 1; + (void) miicv_setint(icvid, MI_ICV_DIM_SIZE+image_dim, + dimsize_list->size[ientry]); + if (n_image_dims < image_dim+1) + n_image_dims = image_dim+1; + } + else { + (void) fprintf(stderr, "Unable to set size of dimension \"%s\"\n", + dimsize_list->name[ientry]); + exit(EXIT_FAILURE); + } + } + + /* Update number of image dimensions, if needed */ + if (n_image_dims > 2) { + (void) miicv_setint(icvid, MI_ICV_NUM_IMGDIMS, n_image_dims); + } + +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : setup_reshaping_info +@INPUT : mincid - id of input minc file + do_norm - indicates if normalization is being done already + through the icv + fillvalue - value to use where there is no input value + do_scalar - TRUE if vector image should be converted to scalar + axis_order - order of dimensions by name + axis_ranges - range of subscripts for each axis + hs_start - starting coordinate of hyperslab to read + hs_count - edge lengths of hyperslab to read + max_chunk_size_in_kb - maximum size of copy buffer in kbytes. +@OUTPUT : reshape_info - information describing the reshaping +@RETURNS : (nothing) +@DESCRIPTION: Routine to set up reshaping information. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : May 26, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void setup_reshaping_info(int icvid, int mincid, + int do_norm, double fillvalue, int do_scalar, + char *axis_order[], Axis_ranges *axis_ranges, + long hs_start[], long hs_count[], + int max_chunk_size_in_kb, + Reshape_info *reshape_info) +{ + int input_ndims, input_dim[MAX_VAR_DIMS], order_dim[MAX_VAR_DIMS]; + int output_ndims, norder; + int idim, jdim, ientry, iloop, order_idim; + int input_dim_used[MAX_VAR_DIMS]; + char name[MAX_NC_NAME]; + int *o2i, *i2o; + nc_type datatype; + int min_ndims, max_ndims, min_dim[MAX_VAR_DIMS], max_dim[MAX_VAR_DIMS]; + int minid, maxid, dimid; + long total_size, size; + int nstart, ncount; + int has_vector_dimension; + int num_imgdims; + int fastest_input_img_dim, fastest_output_img_dim; + int no_chunk_dims_found; + long length; + long first, last; + + /* Get input file dimension info */ + (void) ncvarinq(mincid, ncvarid(mincid, MIimage), NULL, NULL, + &input_ndims, input_dim, NULL); + (void) ncdiminq(mincid, input_dim[input_ndims-1], name, NULL); + has_vector_dimension = (strcmp(name, MIvector_dimension) == 0); + fastest_input_img_dim = (has_vector_dimension ? + input_ndims-2 : input_ndims-1); + if (do_scalar && has_vector_dimension) + input_ndims--; + reshape_info->input_ndims = input_ndims; + + /* Check length of hs_start and hs_count vectors */ + for (nstart=0; (nstart<MAX_VAR_DIMS) && (hs_start[nstart]!=LONG_MIN); + nstart++) {} + for (ncount=0; (ncount<MAX_VAR_DIMS) && (hs_count[ncount]!=LONG_MIN); + ncount++) {} +#if 0 + if ((nstart != 0) && (ncount != 0) && (nstart != ncount)) { + (void) fprintf(stderr, + "Dimensions of start or count vectors not equal.\n"); + exit(EXIT_FAILURE); + } +#endif + if ((ncount > input_ndims) || (nstart > input_ndims)) { + (void) fprintf(stderr, + "Start and/or count vectors are too long.\n"); + exit(EXIT_FAILURE); + } + + /* Get start and count from file info and from hs_start and hs_count */ + (void) miicv_inqint(icvid, MI_ICV_NUM_IMGDIMS, &num_imgdims); + for (idim=0; idim < input_ndims; idim++) { + (void) ncdiminq(mincid, input_dim[idim], NULL, + &reshape_info->input_size[idim]); + if ((idim > fastest_input_img_dim-num_imgdims) && + (idim <= fastest_input_img_dim)) { + (void) miicv_inqlong(icvid, + MI_ICV_DIM_SIZE+fastest_input_img_dim-idim, + &length); + if (length > 0) { + reshape_info->input_size[idim] = length; + } + } + if (idim < nstart) + reshape_info->input_start[idim] = hs_start[idim]; + else + reshape_info->input_start[idim] = 0; + if (idim < ncount) + reshape_info->input_count[idim] = hs_count[idim]; + else + reshape_info->input_count[idim] = reshape_info->input_size[idim]; + } + + /* Get input dimension start and count from axis_ranges variable */ + for (ientry=0; ientry < axis_ranges->nentries; ientry++) { + dimid = ncdimid(mincid, axis_ranges->name[ientry]); + for (idim=0; idim < input_ndims; idim++) { + if (dimid == input_dim[idim]) break; + } + if (idim >= input_ndims) { + (void) fprintf(stderr, "Unknown image dimension \"%s\"\n", + axis_ranges->name[ientry]); + exit(EXIT_FAILURE); + } + reshape_info->input_start[idim] = axis_ranges->start[ientry]; + reshape_info->input_count[idim] = axis_ranges->count[ientry]; + } + + /* Check to see if we will need a fill value */ + reshape_info->need_fillvalue = FALSE; + for (idim=0; idim < input_ndims; idim++) { + first = reshape_info->input_start[idim]; + last = first; + if (reshape_info->input_count[idim] > 0) + last += reshape_info->input_count[idim] - 1; + else if (reshape_info->input_count[idim] < 0) + last += reshape_info->input_count[idim] + 1; + if ((first < 0) || (first >= reshape_info->input_size[idim]) || + (last < 0) || (last >= reshape_info->input_size[idim])) + reshape_info->need_fillvalue = TRUE; + } + + /* Get output dimensions in terms of input */ + + /* Add up number of output dimensions */ + output_ndims = 0; + for (idim=0; idim < input_ndims; idim++) { + if (reshape_info->input_count[idim] != 0) output_ndims++; + } + reshape_info->output_ndims = output_ndims; + + /* Get dim ids for specified order */ + for (norder=0; norder < MAX_VAR_DIMS+1; norder++) { + if (axis_order[norder] == NULL) break; + order_dim[norder] = ncdimid(mincid, axis_order[norder]); + } + if (norder > output_ndims) { + for (idim=0; idim < output_ndims; idim++) { + order_dim[idim] = order_dim[idim + norder - output_ndims]; + } + norder = output_ndims; + } + + /* Keep track of input dims already used in output (dimensions that + are disappearing are considered used) */ + for (idim=0; idim < input_ndims; idim++) { + input_dim_used[idim] = (reshape_info->input_count[idim] == 0); + } + + /* Re-order dimensions */ + for (idim=output_ndims-1; idim >= 0; idim--) { /* Output dim loop */ + order_idim = idim - output_ndims + norder; + for (jdim=input_ndims-1; jdim >= 0; jdim--) { /* Input dim loop */ + /* For specified dimensions, look for corresponding input dim */ + if (order_idim >= 0) { + if (input_dim[jdim] == order_dim[order_idim]) break; + } + /* For remaining dims, take next available */ + else { + if (!input_dim_used[jdim]) break; + } + } + /* Check for error */ + if ((jdim < 0) || input_dim_used[jdim]) { + if (order_idim >= 0) { + (void) fprintf(stderr, + "Cannot re-order dimension \"%s\" (not found, repeated or removed).\n", + axis_order[order_idim]); + } + else { + (void) fprintf(stderr, "Program error in re-ordering axes.\n"); + } + exit(EXIT_FAILURE); + } + /* Save dimension mapping */ + input_dim_used[jdim] = TRUE; + reshape_info->map_out_to_in[idim] = jdim; + } + + /* Get mapping from input to output (-1 means no mapping) */ + for (idim=0; idim < input_ndims; idim++) { + reshape_info->map_in_to_out[idim] = -1; + } + for (idim=0; idim < output_ndims; idim++) { + reshape_info->map_in_to_out[reshape_info->map_out_to_in[idim]] = idim; + } + + /* Get fastest varying output image dimension (excluding vector dim) */ + idim = input_dim[reshape_info->map_out_to_in[output_ndims-1]]; + (void) ncdiminq(mincid, idim, name, NULL); + fastest_output_img_dim = ((strcmp(name, MIvector_dimension) == 0) ? + output_ndims-2 : output_ndims-1); + + /* Save dimensions used in blocks and chunks */ + o2i = reshape_info->map_out_to_in; + i2o = reshape_info->map_in_to_out; + (void) miicv_inqint(reshape_info->icvid, MI_ICV_TYPE, (int *) &datatype); + total_size = nctypelen(datatype); + no_chunk_dims_found = TRUE; + for (idim=0; idim < output_ndims; idim++) { + reshape_info->dim_used_in_block[idim] = FALSE; + reshape_info->chunk_count[idim] = 1; + } + for (iloop=0; iloop < 6; iloop++) { + /* Go through possible dimensions in descending order of priority. + We start with the fastest varying dimension, but allow for the + possibility of vector dimensions in either volume (looping twice + on the same dimension is not a problem). Note that idim refers to + an output dimension. */ + switch (iloop) { + case 0: idim = output_ndims-1; break; + case 1: idim = i2o[input_ndims-1]; break; + case 2: idim = fastest_output_img_dim; break; + case 3: idim = i2o[fastest_input_img_dim]; break; + case 4: idim = fastest_output_img_dim-1; break; + case 5: idim = i2o[fastest_input_img_dim-1]; break; + default: idim = -1; + } + if (idim != -1) size = ABS(reshape_info->input_count[o2i[idim]]); + else size = 0; + if (size == 0) idim = -1; + if ((idim != -1) && !reshape_info->dim_used_in_block[idim]) { + reshape_info->dim_used_in_block[idim] = TRUE; + if (no_chunk_dims_found || + ((total_size * size) <= (max_chunk_size_in_kb * 1024))) { + no_chunk_dims_found = FALSE; + reshape_info->chunk_count[idim] = size; + total_size *= size; + } + } + } + + /* Save fillvalue */ + reshape_info->fillvalue = fillvalue; + + /* Do we need to normalize to slices to a block min and max? */ + if (do_norm) { + reshape_info->do_block_normalization = FALSE; + } + else { + reshape_info->do_block_normalization = FALSE; + + /* Loop through block dimensions and check if image-min/max varies + on the dimension */ + ncopts = 0; + minid = ncvarid(mincid, MIimagemin); + maxid = ncvarid(mincid, MIimagemax); + ncopts = NCOPTS_DEFAULT; + if ((minid != MI_ERROR) && (maxid != MI_ERROR)) { + (void) ncvarinq(mincid, minid, NULL, NULL, &min_ndims, min_dim, NULL); + (void) ncvarinq(mincid, maxid, NULL, NULL, &max_ndims, max_dim, NULL); + for (idim=0; idim < input_ndims; idim++) { + jdim = reshape_info->map_out_to_in[idim]; + if (reshape_info->dim_used_in_block[jdim]) { + dimid = input_dim[jdim]; + for (jdim=0; jdim < min_ndims; jdim++) { + if (min_dim[jdim] == dimid) { + reshape_info->do_block_normalization = TRUE; + } + } + for (jdim=0; jdim < max_ndims; jdim++) { + if (max_dim[jdim] == dimid) { + reshape_info->do_block_normalization = TRUE; + } + } + } + } + } + + } + +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : setup_output_file +@INPUT : mincid - id of output minc file + history - string to be added to history list + reshape_info - information describing the reshaping +@OUTPUT : (none) +@RETURNS : (nothing) +@DESCRIPTION: Routine to set up the output file +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : June 16, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void setup_output_file(int mincid, char *history, + Reshape_info *reshape_info) +{ + int output_ndims, output_dim[MAX_VAR_DIMS]; + int input_ndims, input_dim[MAX_VAR_DIMS]; + int minmax_ndims, minmax_dim[MAX_VAR_DIMS]; + int idim, odim, iloop; + int varid, icvid, imgid, varid2; + char dimname[MAX_NC_NAME]; + long length; + int excluded_vars[2*MAX_VAR_DIMS + 10]; + int nexcluded; + nc_type datatype; + char signtype[MI_MAX_ATTSTR_LEN]; + double valid_range[2]; + char *string; + int att_length; + int has_vector_dimension; + int fastest_img_dim; + + /* Get useful info */ + output_ndims = reshape_info->output_ndims; + (void) ncvarinq(reshape_info->inmincid, + ncvarid(reshape_info->inmincid, MIimage), + NULL, NULL, &input_ndims, input_dim, NULL); + input_ndims = reshape_info->input_ndims; + + /* Check for vector dimension */ + (void) ncdiminq(reshape_info->inmincid, + input_dim[input_ndims-1], dimname, NULL); + has_vector_dimension = (strcmp(dimname, MIvector_dimension) == 0); + fastest_img_dim = (has_vector_dimension ? input_ndims-2 : input_ndims-1); + + /* Create image dimensions */ + for (odim=0; odim < output_ndims; odim++) { + idim = reshape_info->map_out_to_in[odim]; + length = ABS(reshape_info->input_count[idim]); + (void) ncdiminq(reshape_info->inmincid, input_dim[idim], dimname, NULL); + output_dim[odim] = ncdimdef(mincid, dimname, length); + } + + /* Copy all variables except dimensions and dimension widths */ + ncopts = 0; + nexcluded = 0; + for (idim = 0; idim < input_ndims; idim++) { + (void) ncdiminq(reshape_info->inmincid, input_dim[idim], dimname, NULL); + if ((varid=ncvarid(reshape_info->inmincid, dimname)) != MI_ERROR) + excluded_vars[nexcluded++] = varid; + (void) strncat(dimname, DIM_WIDTH_SUFFIX, + sizeof(dimname)-strlen(dimname)-1); + if ((varid=ncvarid(reshape_info->inmincid, dimname)) != MI_ERROR) + excluded_vars[nexcluded++] = varid; + } + if ((varid=ncvarid(reshape_info->inmincid, MIimage)) != MI_ERROR) + excluded_vars[nexcluded++] = varid; + if ((varid=ncvarid(reshape_info->inmincid, MIimagemax)) != MI_ERROR) + excluded_vars[nexcluded++] = varid; + if ((varid=ncvarid(reshape_info->inmincid, MIimagemin)) != MI_ERROR) + excluded_vars[nexcluded++] = varid; + (void) micopy_all_var_defs(reshape_info->inmincid, mincid, + nexcluded, excluded_vars); + ncopts = NCOPTS_DEFAULT; + + /* Create image dimension variables */ + for (odim=0; odim < output_ndims; odim++) { + idim = reshape_info->map_out_to_in[odim]; + create_dim_var(mincid, output_dim[odim], + reshape_info->icvid, + fastest_img_dim - idim, + reshape_info->inmincid, + reshape_info->input_start[idim], + reshape_info->input_count[idim]); + } + + /* Get basic image variable info */ + icvid = reshape_info->icvid; + (void) miicv_inqint(icvid, MI_ICV_TYPE, (int *) &datatype); + (void) miicv_inqstr(icvid, MI_ICV_SIGN, signtype); + (void) miicv_inqdbl(icvid, MI_ICV_VALID_MIN, &valid_range[0]); + (void) miicv_inqdbl(icvid, MI_ICV_VALID_MAX, &valid_range[1]); + + /* Set the valid range to include 0.0 for floating point if needed */ + if (reshape_info->need_fillvalue && + ((datatype == NC_FLOAT) || (datatype == NC_DOUBLE)) && + (reshape_info->fillvalue == NOFILL)) { + if (0.0 < valid_range[0]) valid_range[0] = 0.0; + if (0.0 > valid_range[1]) valid_range[1] = 0.0; + } + + /* Create the image variable */ + imgid = micreate_std_variable(mincid, MIimage, datatype, + output_ndims, output_dim); + reshape_info->outimgid = imgid; + (void) micopy_all_atts(reshape_info->inmincid, + ncvarid(reshape_info->inmincid, MIimage), + mincid, imgid); + (void) miattputstr(mincid, imgid, MIsigntype, signtype); + (void) ncattput(mincid, imgid, MIvalid_range, NC_DOUBLE, 2, valid_range); + (void) miattputstr(mincid, imgid, MIcomplete, MI_FALSE); + + /* Create the imagemax/min variables */ + minmax_ndims = 0; + for (odim=0; odim < output_ndims; odim++) { + if (!reshape_info->dim_used_in_block[odim]) { + minmax_dim[minmax_ndims++] = output_dim[odim]; + } + } + for (iloop=0; iloop < 2; iloop++) { + if (iloop == 0) + string = MIimagemin; + else + string = MIimagemax; + varid = micreate_std_variable(mincid, string, NC_DOUBLE, + minmax_ndims, minmax_dim); + ncopts = 0; + varid2 = ncvarid(reshape_info->inmincid, string); + ncopts = NCOPTS_DEFAULT; + if (varid2 != MI_ERROR) + (void) micopy_all_atts(reshape_info->inmincid, + varid2, mincid, varid); + } + + /* Add history */ + ncopts=0; + if ((ncattinq(mincid, NC_GLOBAL, MIhistory, &datatype, &att_length) + == MI_ERROR) || (datatype != NC_CHAR)) + att_length = 0; + att_length += strlen(history) + 1; + string = MALLOC(att_length); + string[0] = '\0'; + (void) miattgetstr(mincid, NC_GLOBAL, MIhistory, att_length, string); + ncopts = NCOPTS_DEFAULT; + (void) strcat(string, history); + (void) miattputstr(mincid, NC_GLOBAL, MIhistory, string); + FREE(string); + + /* Get into data mode */ + (void) ncsetfill(mincid, NC_NOFILL); + (void) ncendef(mincid); + + /* Copy all the other data */ + (void) micopy_all_var_values(reshape_info->inmincid, mincid, + nexcluded, excluded_vars); + + /* Copy the dimension variable values, if needed */ + for (odim=0; odim < output_ndims; odim++) { + idim = reshape_info->map_out_to_in[odim]; + copy_dimension_values(mincid, output_dim[odim], + reshape_info->inmincid, + reshape_info->input_start[idim], + reshape_info->input_count[idim]); + } + +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : create_dim_var +@INPUT : outmincid - id of output minc file + outdimid - id of output dimension + inicvid - id of input icv + cur_image_dim - image dim number of current dimension in + input icv (0 is fastest varying dimension) + inmincid - id of input minc file + input_start - start index of input dimension + input_count - count for input dimension (may be negative) +@OUTPUT : (none) +@RETURNS : (nothing) +@DESCRIPTION: Creates a dimension variable and sets attributes properly. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : June 16, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void create_dim_var(int outmincid, int outdimid, + int inicvid, int cur_image_dim, int inmincid, + long input_start, long input_count) +{ + int invarid, outvarid; + int num_image_dims, var_ndims; + int is_regular, step_found, start_found, changed_spacing; + double dim_start, dim_step, icv_start, icv_step; + char dimname[MAX_NC_NAME]; + char spacing[MAX_NC_NAME]; + + /* Get the dimension name */ + (void) ncdiminq(outmincid, outdimid, dimname, NULL); + + /* Get number of image dimensions */ + (void) miicv_inqint(inicvid, MI_ICV_NUM_IMGDIMS, &num_image_dims); + + /* Get step and start and spacing for dimension */ + dim_step = 1.0; + dim_start = 0.0; + is_regular = TRUE; + changed_spacing = ((input_start != 0) || (input_count <= 0)); + ncopts = 0; + invarid = ncvarid(inmincid, dimname); + if (invarid != MI_ERROR) { + step_found = (miattget1(inmincid, invarid, MIstep, NC_DOUBLE, + &dim_step) != MI_ERROR); + start_found = (miattget1(inmincid, invarid, MIstart, NC_DOUBLE, + &dim_start) != MI_ERROR); + (void) ncvarinq(inmincid, invarid, NULL, NULL, &var_ndims, NULL, NULL); + if (var_ndims > 0) { + (void) strcpy(spacing, MI_IRREGULAR); + (void) miattgetstr(inmincid, invarid, MIspacing, sizeof(spacing), + spacing); + is_regular = (strcmp(spacing, MI_REGULAR) == 0); + } + } + ncopts = NCOPTS_DEFAULT; + + /* Is the sampling changed because of the icv? */ + if ((cur_image_dim < num_image_dims) && (cur_image_dim >= 0)) { + (void) miicv_inqdbl(inicvid, MI_ICV_DIM_STEP+cur_image_dim, &icv_step); + (void) miicv_inqdbl(inicvid, MI_ICV_DIM_START+cur_image_dim, &icv_start); + if ((icv_step != dim_step) || (icv_start != dim_start)) { + dim_step = icv_step; + dim_start = icv_start; + is_regular = TRUE; + changed_spacing = TRUE; + } + } + + /* If spacing is not changed and the input variable does not exist don't + create the variable */ + if (!changed_spacing && (invarid == MI_ERROR)) + return; + + /* Calculate the new dim_start and dim_step (if needed) */ + dim_start += input_start * dim_step; + if (input_count < 0) dim_step = -dim_step; + + /* Create the variable */ + var_ndims = (is_regular ? 0 : 1); + ncopts = 0; + outvarid = micreate_std_variable(outmincid, dimname, NC_DOUBLE, + var_ndims, &outdimid); + ncopts = NCOPTS_DEFAULT; + if (outvarid == MI_ERROR) { + outvarid = ncvardef(outmincid, dimname, NC_DOUBLE, var_ndims, &outdimid); + } + if (invarid != MI_ERROR) + (void) micopy_all_atts(inmincid, invarid, outmincid, outvarid); + if (is_regular || step_found) + (void) miattputdbl(outmincid, outvarid, MIstep, dim_step); + if (is_regular || start_found) + (void) miattputdbl(outmincid, outvarid, MIstart, dim_start); + + /* Create width variable if needed */ + ncopts = 0; + (void) strncat(dimname, DIM_WIDTH_SUFFIX, + sizeof(dimname)-strlen(dimname)-1); + invarid = ncvarid(inmincid, dimname); + if (invarid != MI_ERROR) { + (void) ncvarinq(inmincid, invarid, NULL, NULL, &var_ndims, NULL, NULL); + if (var_ndims > 0) var_ndims = 1; + outvarid = micreate_std_variable(outmincid, dimname, NC_DOUBLE, + var_ndims, &outdimid); + if (outvarid == MI_ERROR) { + outvarid = ncvardef(outmincid, dimname, NC_DOUBLE, + var_ndims, &outdimid); + } + if (invarid != MI_ERROR) + (void) micopy_all_atts(inmincid, invarid, outmincid, outvarid); + } + ncopts = NCOPTS_DEFAULT; + +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : copy_dimension_values +@INPUT : outmincid - id of output minc file + outdimid - id of output dimension + inmincid - id of input minc file + input_start - start index of input dimension + input_count - length of input dimension +@OUTPUT : (none) +@RETURNS : (nothing) +@DESCRIPTION: Copies the data for a dimension variable. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : June 16, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void copy_dimension_values(int outmincid, int outdimid, int inmincid, + long input_start, long input_count) +{ + char dimname[MAX_NC_NAME]; + char varname[MAX_NC_NAME]; + + /* Get the dimension name */ + (void) ncdiminq(outmincid, outdimid, dimname, NULL); + (void) strcpy(varname, dimname); + + /* Copy the dimension coorindates */ + copy_dim_var_values(outmincid, dimname, varname, inmincid, + input_start, input_count); + + /* Copy the dimension widths */ + (void) strncat(varname, DIM_WIDTH_SUFFIX, + sizeof(varname)-strlen(varname)-1); + copy_dim_var_values(outmincid, dimname, varname, inmincid, + input_start, input_count); + +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : copy_dim_var_values +@INPUT : outmincid - id of output minc file + dimname - name of dimension + varname - name of variable to copy + inmincid - id of input minc file + input_start - start index of input dimension + input_count - length of input dimension +@OUTPUT : (none) +@RETURNS : (nothing) +@DESCRIPTION: Copies the data for a dimension variable. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : June 16, 1994 (Peter Neelin) +@MODIFIED : +---------------------------------------------------------------------------- */ +public void copy_dim_var_values(int outmincid, char *dimname, char *varname, + int inmincid, + long input_start, long input_count) +{ + int invarid, outvarid; + int in_ndims, in_dim[MAX_VAR_DIMS], out_ndims; + char string[MAX_NC_NAME]; + int good_data, is_width, flip_dimension; + long output_index, input_index, index, input_length; + double value, dim_width, dim_step, dim_start; + + /* Do we need to copy data? */ + ncopts = 0; + outvarid = ncvarid(outmincid, varname); + ncopts = NCOPTS_DEFAULT; + if (outvarid == MI_ERROR) return; + (void) ncvarinq(outmincid, outvarid, NULL, NULL, &out_ndims, NULL, NULL); + if (out_ndims != 1) return; + + /* Is this a width variable? */ + index = strlen(varname) - strlen(DIM_WIDTH_SUFFIX); + if (index < 0) + is_width = FALSE; + else + is_width = (strcmp(&varname[index], DIM_WIDTH_SUFFIX)); + + /* Check if there is a valid dimension variable from which to copy */ + ncopts = 0; + invarid = ncvarid(inmincid, varname); + ncopts = NCOPTS_DEFAULT; + good_data = (invarid != MI_ERROR); + if (good_data) { + (void) ncvarinq(inmincid, invarid, NULL, NULL, &in_ndims, in_dim, NULL); + good_data = (in_ndims == 1); + } + if (good_data) { + (void) ncdiminq(inmincid, in_dim[0], string, &input_length); + good_data = (strcmp(string, dimname) == 0); + } + + /* Get data from input file for estimating unknown values */ + if (is_width) { /* Get width for width variables */ + dim_width = 0.0; + ncopts = 0; + (void) miattget1(inmincid, invarid, MIwidth, NC_DOUBLE, &dim_width); + ncopts = NCOPTS_DEFAULT; + } + else { /* Get step and start for coordinate variables */ + dim_step = 1.0; + dim_start = 0.0; + if (good_data) { + input_index = 0; + (void) mivarget1(inmincid, invarid, &input_index, NC_DOUBLE, NULL, + &dim_start); + input_index = input_length - 1; + if (input_length <= 1) { + ncopts = 0; + (void) miattget1(inmincid, invarid, MIstep, NC_DOUBLE, &dim_step); + ncopts = NCOPTS_DEFAULT; + } + else { + (void) mivarget1(inmincid, invarid, &input_index, NC_DOUBLE, NULL, + &value); + dim_step = (value - dim_start) / ((double) input_length - 1); + } + } + else { + ncopts = 0; + (void) miattget1(inmincid, invarid, MIstep, NC_DOUBLE, &dim_step); + (void) miattget1(inmincid, invarid, MIstart, NC_DOUBLE, &dim_start); + ncopts = NCOPTS_DEFAULT; + } + if (dim_step == 0.0) dim_step = 1.0; + } + + /* Loop through output values */ + flip_dimension = (input_count < 0); + input_count = ABS(input_count); + for (output_index=0; output_index < input_count; output_index++) { + + /* Get input value */ + if (!flip_dimension) { + input_index = input_start + output_index; + } + else { + input_index = input_start - output_index; + } + if (good_data && (input_index >= 0) && (input_index < input_length)) { + (void) mivarget1(inmincid, invarid, &input_index, NC_DOUBLE, NULL, + &value); + } + else { + if (is_width) { + value = dim_width; + } + else { + value = input_index * dim_step + dim_start; + } + } + (void) mivarput1(outmincid, outvarid, &output_index, NC_DOUBLE, NULL, + &value); + + } + +} +
new file mode 100644 --- /dev/null +++ b/progs/mincreshape/mincreshape.h @@ -0,0 +1,150 @@ +/* ----------------------------- MNI Header ----------------------------------- +@NAME : mincreshape.h +@DESCRIPTION: Header file for mincreshape.c +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : March 11, 1994 (Peter Neelin) +@MODIFIED : $Log: mincreshape.h,v $ +@MODIFIED : Revision 1.1 1994-11-02 16:22:00 neelin +@MODIFIED : Initial revision +@MODIFIED : +@COPYRIGHT : + Copyright 1993 Peter Neelin, McConnell Brain Imaging Centre, + Montreal Neurological Institute, McGill University. + Permission to use, copy, modify, and distribute this + software and its documentation for any purpose and without + fee is hereby granted, provided that the above copyright + notice appear in all copies. The author and McGill University + make no representations about the suitability of this + software for any purpose. It is provided "as is" without + express or implied warranty. +---------------------------------------------------------------------------- */ + +/* Constants used in program */ +#define NOFILL DBL_MAX /* Fillvalue indicating -nofill */ +#define FILL -DBL_MAX /* Fillvalue for -fill */ +#define NCOPTS_DEFAULT NC_VERBOSE | NC_FATAL +#define DEFAULT_MAX_CHUNK_SIZE_IN_KB (1024*4) +#define DIM_WIDTH_SUFFIX "-width" +#define VECTOR_SEPARATOR ',' +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif + +/* Types used in program */ + +typedef struct { + int verbose; + int icvid, inmincid, outmincid, outimgid; + nc_type output_datatype; + int output_is_signed; + int input_ndims; /* Number of input dimensions */ + int output_ndims; /* Number of output dimensions */ + long input_size[MAX_VAR_DIMS]; /* Size of input volume */ + long input_start[MAX_VAR_DIMS]; /* Start of desired hyperslab */ + long input_count[MAX_VAR_DIMS]; /* Size of desired hyperslab + (<0 means 1 and remove dimension) */ + int map_out_to_in[MAX_VAR_DIMS]; /* Map output dimension index to input */ + int map_in_to_out[MAX_VAR_DIMS]; /* Map input dimension index to output + (-1 means no mapping) */ + int dim_used_in_block[MAX_VAR_DIMS]; /* TRUE if output dim used in block */ + int chunk_count[MAX_VAR_DIMS]; /* Specifies count for chunk hyperslab */ + int need_fillvalue; /* TRUE if we will need a fill value */ + double fillvalue; /* Value to fill with (FILL_DEFAULT + means fill with real value zero) */ + int do_block_normalization; /* Normalize slices to block max/min */ + + /* Note that a block is a hyperslab of the output volume in which all + values are normalized the same way. A chunk is a hyperslab that is + copied in one piece (smaller than or equal to a block). */ + +} Reshape_info; + +typedef struct { + int nentries; + char *name[MAX_VAR_DIMS]; + long size[MAX_VAR_DIMS]; +} Dimsize_list; + +typedef struct { + int nentries; + char *name[MAX_VAR_DIMS]; + long start[MAX_VAR_DIMS]; + long count[MAX_VAR_DIMS]; +} Axis_ranges; + +/* Macros used in program */ +#define ISSPACE(ch) (isspace((int)ch)) +#define ABS(x) (((x) >= 0) ? (x) : (-(x))) +#define MAX( x, y ) ( ((x) >= (y)) ? (x) : (y) ) +#define MIN( x, y ) ( ((x) <= (y)) ? (x) : (y) ) + +/* Function prototypes */ +public int main(int argc, char *argv[]); +public void get_arginfo(int argc, char *argv[], + Reshape_info *reshape_info); +public int get_fillvalue(char *dst, char *key, char *nextArg); +public int get_dimsize(char *dst, char *key, char *nextArg); +public int get_axis_order(char *dst, char *key, char *nextArg); +public int get_axis_range(char *dst, char *key, char *nextArg); +public int get_arg_vector(char *dst, char *key, char *nextArg); +public void get_default_datatype(int mincid, nc_type *datatype, int *is_signed, + double valid_range[2]); +public void setup_dim_sizes(int icvid, int mincid, Dimsize_list *dimsize_list); +public void setup_reshaping_info(int icvid, int mincid, + int do_norm, double fillvalue, int do_scalar, + char *axis_order[], Axis_ranges *axis_ranges, + long hs_start[], long hs_count[], + int max_chunk_size_in_kb, + Reshape_info *reshape_info); +public void setup_output_file(int mincid, char *history, + Reshape_info *reshape_info); +public void create_dim_var(int outmincid, int outdimid, + int inicvid, int cur_image_dim, int inmincid, + long input_start, long input_count); +public void copy_dimension_values(int outmincid, int outdimid, int inmincid, + long input_start, long input_count); +public void copy_dim_var_values(int outmincid, char *dimname, char *varname, + int inmincid, + long input_start, long input_count); +public void copy_data(Reshape_info *reshape_info); +public void get_num_minmax_values(Reshape_info *reshape_info, + long *block_start, long *block_count, + long *num_min_values, long *num_max_values); +public void handle_normalization(Reshape_info *reshape_info, + long *block_start, + long *block_count, + double *minmax_buffer, + double *fillvalue); +public void truncate_input_vectors(Reshape_info *reshape_info, + long *input_start, + long *input_count); +public void translate_output_to_input(Reshape_info *reshape_info, + long *output_start, + long *output_count, + long *input_start, + long *input_count); +public void translate_input_to_output(Reshape_info *reshape_info, + long *input_start, + long *input_count, + long *output_start, + long *output_count); +public void copy_the_chunk(Reshape_info *reshape_info, + long chunk_start[], + long chunk_count[], + void *chunk_data, + double fillvalue); +public void convert_value_from_double(double dvalue, + nc_type datatype, int is_signed, + void *ptr); +public void nd_begin_looping(long start[], long current[], int ndims); +public int nd_end_of_loop(long start[], long end[], int ndims); +public void nd_update_current_count(long current[], + long increment[], long end[], + long current_count[], + int ndims); +public void nd_increment_loop(long current[], + long start[], long increment[], long end[], + int ndims);
new file mode 100644 --- /dev/null +++ b/progs/mincreshape/mincreshape.man1 @@ -0,0 +1,347 @@ +.\" Copyright 1994 Peter Neelin, McConnell Brain Imaging Centre, +.\" Montreal Neurological Institute, McGill University. +.\" Permission to use, copy, modify, and distribute this +.\" software and its documentation for any purpose and without +.\" fee is hereby granted, provided that the above copyright +.\" notice appear in all copies. The author and McGill University +.\" make no representations about the suitability of this +.\" software for any purpose. It is provided "as is" without +.\" express or implied warranty. +.\" +.\" $Header: /private-cvsroot/minc/progs/mincreshape/mincreshape.man1,v 1.1 1994-11-02 16:22:08 neelin Exp $ +.\" +.TH MINCRESHAPE 1 "MINC Image File Format" + +.SH NAME +mincreshape - cuts a hyperslab out of a minc file (with dimension re-ordering) + +.SH SYNOPSIS +.B mincreshape +[<options>] <infile>.mnc <outfile>.mnc + +.SH DESCRIPTION +.I Mincreshape's +main job is to chop a hyperslab out of a minc file and put it into a +new minc file. "What is a hyperslab?", you ask. It is simply a +multi-dimensional box specified with a starting index (a vector giving +a voxel coordinate) and a count vector (a number of voxels along each +axis). A single slice out of a volume is a hyperslab (with a count of +1 in the slice direction), a small block pulled out of a large volume +is a hyperslab, a single echo volume out of a multi-echo MRI dataset +is a hyperslab, one time point out of a dynamic acquisition is a +hyperslab - you get the idea. Check out the -start, -count and +-dimrange options for more details on how to do this (and look at the +examples!). If you are pulling out only one point along a dimension, +you have the option of making the dimension disappear, so mincreshape +gives you the ability to reduce the dimensionality of a minc file. As +well, you aren't constrained to specify a hyperslab that is only +within the input file, you can extend beyond the bounds of the +dimensions in the input file, and furthermore you can give a count +that will flip the data along a dimension. + +As if all that is not enough +.I mincreshape +has the ability to re-order dimensions. The most obvious case is +converting a transverse image into a coronal image. But you can +type a list of dimension names to get an arbitrary order of +dimensions. + +You want more!?! Okay, okay. +.I mincreshape +makes all of the minc library icv conversions available on the command +line. The include changing type, range and normalization of the pixel +values, expanding or contracting images (by pixel duplication or +averaging) to give a specified image size, and converting vector +images to scalar. + +Just so you don't get confused let me tell you clearly here: +.I Mincreshape +does all of the icv conversions first and then the hyperslab and +dimension re-ordering stuff is applied to the result of that. So if +you want to mix them together (like -imgsize, -start, -count), get it +clear in your head first. + +Okay, hold on to your seat: here's a list of options. + +.SH OPTIONS +Note that options can be specified in abbreviated form (as long as +they are unique) and can be given anywhere on the command line. + +.SH General options +.P +.I -clobber: +Overwrite an existing file. +.P +.I -noclobber: +Don't overwrite an existing file (default). +.P +.I -verbose: +Print out progress information for each chunk of data copied +(default). A chunk varies in size depending mostly on whether you're +re-ordering dimensions or not and how big the internal buffer is +allowed to be. +.P +.I -quiet: +Do not print out progress information. +.P +.I -max_chunk_size_in_kb: +Specify the maximum size of the copy buffer (in kbytes). Default is +4096 kbytes. + +.SH Image conversion options (pixel type and range): +The default for type, sign and valid range is to use those of the input +file. If type is specified, then both sign and valid range are set to +the default for that type. If sign is specified, then valid range is +set to the default for the type and sign. +.P +.I -filetype: +Don't do any type conversion (default). +.P +.I -byte: +Write out bytes values. +.P +.I -short: +Write out short integer values. +.P +.I -long: +Write out long integer values. +.P +.I -float: +Write out single-precision floating point values. +.P +.I -double: +Write out double-precision floating point values. +.P +.I -signed: +Write out values as signed integers (default for short and long). Ignored for +floating point types. +.P +.I -unsigned: +Write out values as unsigned integers (default for byte). Ignored for +floating point types. +.P +.I -valid_range +<min> <max>: +specifies the valid range of output voxel values in their integer +representation. Default is the full range +for the type and sign. This option is ignored for floating point +values. +.P +.I -image_range: +<min> <max> +Normalize images to a given minimum and maximum real value (not voxel +value). +.P +.I -normalize: +Normalize images to real minimum and maximum for the entire input +file. +.P +.I -nonormalize: +Do not normalize images (default). +.P +.I -nopixfill: +Do not convert out-of-range values in input file, just copy them +through. +.P +.I -pixfill: +Replace out-of-range values in input file by the smallest possible +value (default). +.P +.I -pixfillvalue +<value>: +Specify a new pixel value to replace out-of-range values in the input +file. + +.SH Image conversion options (dimension direction and size): +.P +.I -scalar: +Convert vector images to scalar images (a vector image is one with +vector_dimension as the fastest varying dimension). The vector +dimension is removed and values are averaged. +.P +.I -noscalar: +Do not convert vector images to scalar images (default). +.P +.I +direction: +Flip images to give positive step value for spatial axes. +Note that the flipping of spatial axes only applies to "image +dimensions". These are the two fastest varying (non-vector) dimensions +in the file. If you want to flip a non-image dimension, you can +convert it to an image dimension with -dimsize <dimname>=-1 (the -1 +means don't really change the size). Check out the examples. +.P +.I -direction: +Flip images to give negative step value for spatial axes. +.P +.I -anydirection: +Don't flip images along spatial axes (default). +.P +.I +xdirection: +Flip images to give positive xspace:step value (left-to-right). +.P +.I -xdirection: +Flip images to give negative xspace:step value (right-to-left). +.P +.I -xanydirection: +Don't flip images along x-axis. +.P +.I +ydirection: +Flip images to give positive yspace:step value (posterior-to-anterior). +.P +.I -ydirection: +Flip images to give negative yspace:step value (anterior-to-posterior). +.P +.I -yanydirection: +Don't flip images along y-axis. +.P +.I +zdirection: +Flip images to give positive zspace:step value (inferior-to-superior). +.P +.I -zdirection: +Flip images to give negative zspace:step value (superior-to-inferior). +.P +.I -zanydirection: +Don't flip images along z-axis. +.P +.I -keepaspect: +Preserve aspect ratio when resizing images. This means that voxels are +replicated (or averaged) the same number of times along each image +dimension. +.P +.I -nokeepaspect: +Do not force preservation of aspect ratio when resizing images (default). +.P +.I -imgsize +<size>: +Specify the desired image size (used if -rowsize or -colsize not +given). +.P +.I -rowsize +<size>: +Specify the desired number of rows in the image. +.P +.I -colsize +<size>: +Specify the desired number of columns in the image. +.P +.I -dimsize +<dimension>=<size> +Specify the size of a named dimension (<dimension>=<size>). Note that +the resizing only applies to "image dimensions" - usually the two +fastest-varying (non-vector) dimensions. To do dimension resizing, all +fastest-varying dimensions up to the named dimension are turned into +image dimensions, and these are then affected by the direction +options. The dimension name and size must be in one command-line +argument, so if you use spaces (which is okay), remember to use quotes +to hide them from the shell. + +.SH Reshaping options: +.P +.I -transverse: +Write out transverse slices. +.P +.I -sagittal: +Write out sagittal slices. +.P +.I -coronal: +Write out coronal slices. +.P +.I -dimorder +<dim1>,<dim2>,<dim3>,...: +Specify dimension order, where <dim?> are the names of the dimensions. +You can give fewer dimensions than exist in the file: they are assumed +to be the fastest varying dimensions in the output file (so +-transverse is exactly equivalent to -dimorder zspace,yspace,xspace). +Again, spaces are allowed between names, but remember to hide them +from the shell with quotes. +.P +.I -dimrange +<dim>=<start>[,<count>]: +Specify the range of dimension subscripts for dimension <dim>. If +<count> is missing or 0, then it is taken to mean 1, but remove the +dimension from the output file (a count of 1 will keep a dimension of +size 1). A negative <count> means flip the data along that dimension - +in this case <start> specifies the highest voxel coordinate for the +dimension (-dimrange xspace=3,-3 gives a flipped version of -dimrange +xspace=1,3). The options -start and -count provide an alternative way +to specify the same information. +.P +.I -start +<coord0>,<coord1>,<coord2>,...: +Specifies the starting corner of the hyperslab (coordinates go from +slowest varying dimension to fastest). If fewer coordinates are given than +dimensions exist in the file, then they are assumed to apply +to the slowest varying dimensions and the remaining coordinates are +set to 0. See -dimrange for more details. +.P +.I -count +<size0>,<size1>,<size2>,...: +Specifies edge lengths of hyperslab to read (coordinates go from +slowest varying dimension to fastest). If fewer sizes are given than +dimensions exist in the file, then they are assumed to apply to the +slowest varying dimensions and the remaining sizes are set to the full +size of the dimension. See -dimrange for more details. + +.SH Missing data options: +.P +.I -nofill: +Use value zero for points outside of the input volume (default). +.P +.I -fill: +Use a fill value for points outside of input volume (minimum possible +value). +.P +.I -fillvalue +<fillvalue>: +Specify a fill value for points outside of the input volume (this is a +real value, not a pixel value). + +.SH Generic options for all commands: +.P +.I -help: +Print summary of command-line options and abort. + +.SH EXAMPLES: + +Assume that we have a volume with dimensions zspace,yspace,xspace and +sizes 128,256,256. If we want to get slice 40 out of it (keeping the +coordinate information for the zspace dimension), then we can use + mincreshape original.mnc new.mnc \\ + -dimrange zspace=40,1 + +Alternatively, we could use + mincreshape original.mnc new.mnc \\ + -start 40,0,0 -count 1,256,256 + +Or simply + mincreshape original.mnc new.mnc \\ + -start 40 -count 1 + +If we wanted to get rid of the zspace dimension, we could use + mincreshape original.mnc new.mnc \\ + -dimrange zspace=40,0 + +Let's get a block out of the middle and flip it along xspace: + mincreshape original.mnc new.mnc \\ + -start 40,10,240 -count 1,200,-200 + +But why restrain outselves? Let's go out of bounds: + mincreshape original.mnc new.mnc \\ + -start 40,-100,340 -count 1,200,-200 + +How about some sideways heads - flip x and y. And convert to byte to +save space while we're at it: + mincreshape original.mnc new.mnc \\ + -dimorder xspace,yspace -byte + +Let's make sure that all dimensions have a negative step attribute +(see option +direction for some details): + mincreshape original.mnc new.mnc \\ + -direction -dimsize zspace=-1 + +.SH AUTHOR +Peter Neelin + +.SH COPYRIGHTS +.ps 18 +\fB\(co\fR\s12 Copyright 1994 by Peter Neelin