MINC/Tutorials/Programming03

A fully functional and useful example

edit

There are two programs that can be found inside the conglomerate package: print_volume_value and print_world_value. To use them you specify a minc volume and xyz coordinates in either voxel (volume) or world space, and it returns the real value at that location. Here we will combine that functionality into a single minc2 program.

The code is presented in its entirety below, with commentary at the end of this page. The usage is the following:

> minc2_tutorial3 input.mnc v|w c1 c2 c3

Where v or w specify whether world or voxel coordinates are specified inside c1 c2 c3.

#include <minc2.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

int main(int argc, char **argv) {
  mihandle_t    minc_volume;
  midimhandle_t dimensions[3];
  double        voxel;
  int           result, i;
  double        world_location[3];
  double        dvoxel_location[3];
  unsigned long voxel_location[3];
  unsigned int  sizes[3];
  char          *usage;
  char          voxel_or_world;
  
  usage = "minc2_tutorial3 input.mnc v|w x y z";
  
  if (argc != 6) {
    fprintf(stderr, "USAGE: %s\n", usage);
    return(1);
  }

  /* open the volume - first command line argument */
  result = miopen_volume(argv[1], MI2_OPEN_READ, &minc_volume);
  /* check for error on opening */
  if (result != MI_NOERROR) {
    fprintf(stderr, "Error opening input file: %d.\n", result);
    fprintf(stderr, "%s", usage);
    return(1);
  }

  /* check for whether voxel or world coordinates are specified */
  voxel_or_world = argv[2][0];

  /* handle the case of world coordinates */
  if (strcmp(&voxel_or_world, "w") == 0) {
    /* get the world coordinates from the command line */
    world_location[0] = atof(argv[3]);
    world_location[1] = atof(argv[4]);
    world_location[2] = atof(argv[5]);

    /* convert world coordinates to voxel coordinates */
    result = miconvert_world_to_voxel(minc_volume, world_location, 
				      dvoxel_location);
    if (result != MI_NOERROR) {
      fprintf(stderr, 
	      "Error converting world coordinates to voxel coordinates\n");
      fprintf(stderr, "%s", usage);
      return(1);
    }

  }
  /* handle the case of voxel coordinates */
  else if (strcmp(&voxel_or_world, "v") == 0) {
    dvoxel_location[0] = atof(argv[3]);
    dvoxel_location[1] = atof(argv[4]);
    dvoxel_location[2] = atof(argv[5]);
    /* convert the voxel coordinates to world coordinates */
    miconvert_voxel_to_world(minc_volume, dvoxel_location,
			     world_location);
  }
  /* only v and w are allowed for this argument */
  else {
    fprintf(stderr, "Must specify v or w for voxel or world\n");
    return(1);
  }

  /* miconvert_world_to_voxel needs an array of doubles     *
   * but miget_real_value needs unsigned longs - so we cast */
  for (i=0; i<3; i++) { 
    voxel_location[i] = (unsigned long) dvoxel_location[i];
  }


  /* get the dimension sizes and make sure that  *
   * we are using legal coordinates              */
  miget_volume_dimensions(minc_volume, MI_DIMCLASS_SPATIAL,
			  MI_DIMATTR_ALL, MI_DIMORDER_FILE,
			  3, dimensions);
  result = miget_dimension_sizes(dimensions, 3, sizes);
  printf("Volume sizes: %u %u %u\n", sizes[0], sizes[1], sizes[2]);

  /* die with an error if voxel coordinates are out of bounds */
  for(i=0; i<3; i++) {
    assert(voxel_location[i] >= 0 && voxel_location[i] < sizes[i]);
  }

  /* print the world to voxel mapping */
  printf("Voxel location of xyz %f %f %f: %lu %lu %lu\n", 
	 world_location[0], world_location[1], world_location[2],
	 voxel_location[0], voxel_location[1], voxel_location[2]);

  /* print the value at that location */
  miget_real_value(minc_volume, voxel_location, 3, &voxel);
  printf("Voxel at xyz %f %f %f was: %f\n", 
	 world_location[0], world_location[1], world_location[2], voxel);

  return(0);
}

Most of this code you've seen in the two previous examples. There are a few additional minc library calls - the first is miconvert_voxel_to_world, which does the reverse of miconvert_world_to_voxel. There are also two functions that deal with dimensions. The first, miget_volume_dimensions, places the dimensions associated with the specified minc volume into a midimhandle_t variable. There are several arguments to this function; for the moment it is sufficient to note that the defaults used above will be fine for most cases (and the details will be discussed in a later tutorial). The next function is crucial - miget_dimension_sizes returns the number of elements in each dimension. This is crucial information for looping over voxels as will be illustrated later.

As stated above this code reproduces functionality that exists in print_volume_value and print_world_value. It does, however, illustrate one advantage of minc2 over volume_io (the older library used by those two programs): it is much faster, by as much as an order of magnitude for this example.