Get Teem at SourceForge.net. Fast, secure and Free Open Source software downloads
Teem / Nrrd

  Library Description

  1. Data Structures
  2. Input/Output functions, with error reporting
  3. Reading a NRRD with a different memory allocator
  4. Getting data into and out of nrrds
  5. Setting/Getting per-axis information
  6. Key/Value Pairs
  7. Space and Orientation
  8. Overview of rest of API

This page is intended to be a basic introduction to programming with the Nrrd API. The stand-alone NrrdIO library includes all the functions described in Section 1 through 7; it lacks the functions (listed in Section 8) which perform non-trivial manipulations of the array values. This page will make the most sense if you already know what sort of data and meta-data can be represented in a nrrd. The Introduction to Nrrd is useful in this respect, as is the General Description of the NRRD Format. The Definition of NRRD File Format is a detailed and "bottom-up" view of what can go into a nrrd, from the standpoint of the written file. This will do the same thing, from the standpoint of what is available as data structures in memory.

1. Data Structures

We start with the Nrrd data structure. This comes in two parts: the struct for per-axis information (NrrdAxis), and the main Nrrd struct which includes an array of NrrdAxiss. These are extracted from teem/src/nrrd/nrrd.h (or NrrdIO.h).
/*
******** NrrdAxisInfo struct
**
** all the information which can sensibly be associated with
** one axis of a nrrd.  The only member which MUST be explicitly
** set to something meaningful is "size".
**
** If an axis lies conceptually along some direction in an enclosing
** space of dimension nrrd->spaceDim, then the first nrrd->spaceDim
** entries of spaceDirection[] must be non-NaN, and min, max, spacing,
** and units must NOT be set;  thickness, center, and label can still
** be used.  The mutual exclusion between axis-aligned and general
** direction information is enforced per-axis, not per-array.
**
** The min and max values give the range of positions "represented"
** by the samples along this axis.  In node-centering, "min" IS the
** position at the lowest index.  In cell-centering, the position at
** the lowest index is between min and max (a touch bigger than min,
** assuming min < max).
**
** There needs to be a one-to-one correspondence between these variables
** and the nrrdAxisInfo* enum (nrrdEnums.h), the per-axis header fields
** (see nrrdField* enum in nrrdEnums.h), and the various methods in axis.c
*/
typedef struct {
  size_t size;              /* number of elements along each axis */
  double spacing;           /* if non-NaN, distance between samples */
  double thickness;         /* if non-NaN, nominal thickness of region
                               represented by one sample along the axis. No
                               semantics relative to spacing are assumed or
                               imposed, and unlike spacing, there is no
                               sensible way to alter thickness- it is either
                               copied (as with cropping and slicing) or set to
                               NaN (when resampled). */
  double min, max;          /* if non-NaN, range of positions spanned by the
                               samples on this axis.  Obviously, one can set
                               "spacing" to something incompatible with min
                               and max: the idea is that only one (min and
                               max, or spacing) should be taken to be
                               significant at any time. */
  double spaceDirection[NRRD_SPACE_DIM_MAX]; 
                            /* the vector, in "space" (as described by
                               nrrd->space and/or nrrd->spaceDim), from one
                               sample to the next sample along this axis.  It
                               is the column vector of the transform from
                               index space to "space" space */
  int center;               /* cell vs. node centering (value should be one of
                               nrrdCenter{Unknown,Node,Cell} */
  int kind;                 /* what kind of information is along this axis
                               (from the nrrdKind* enum) */
  char *label,              /* short info string for each axis */
    *units;                 /* string identifying the unit */
} NrrdAxisInfo;

/*
******** Nrrd struct
**
** The struct used to wrap around the raw data array
*/
typedef struct {
  /* 
  ** NECESSARY information describing the main array.  This is
  ** generally set at the same time that either the nrrd is created,
  ** or at the time that the nrrd is wrapped around an existing array 
  */

  void *data;                       /* the data in memory */
  int type;                         /* a value from the nrrdType enum */
  unsigned int dim;                 /* the dimension (rank) of the array */

  /* 
  ** All per-axis specific information
  */
  NrrdAxisInfo axis[NRRD_DIM_MAX];  /* axis[0] is the fastest axis in the scan-
                                       line ordering, the one who's coordinates
                                       change the fastest as the elements are
                                       accessed in the order in which they
                                       appear in memory */

  /* 
  ** Optional information descriptive of whole array, some of which is
  ** meaningfuly for only some uses of a nrrd
  */
  char *content;                    /* brief account of what this data is */
  char *sampleUnits;                /* units of measurement of the values 
                                       stored in the array itself (not the 
                                       array axes and not space coordinates).
                                       The logical name might be "dataUnits",
                                       but that's perhaps ambiguous.  Note that
                                       these units may apply to non-scalar
                                       kinds (e.g. coefficients of a vector
                                       have the same units) */
  int space;                        /* from nrrdSpace* enum, and often 
                                       implies the value of spaceDim */
  unsigned int spaceDim;            /* if non-zero, the dimension of the space
                                       in which the regular sampling grid
                                       conceptually lies.  This is a separate
                                       variable because this dimension can be
                                       different than the array dimension. 
                                       The non-zero-ness of this value is in 
                                       fact the primary indicator that space
                                       and orientation information is set.
                                       This identifies the number of entries in
                                       "origin" and the per-axis "direction"
                                       vectors that are taken as meaningful */
  char *spaceUnits[NRRD_SPACE_DIM_MAX];
                                    /* units for coordinates of space */
  double spaceOrigin[NRRD_SPACE_DIM_MAX];
                                    /* the location of the center the first
                                       (lowest memory address) array sample,
                                       regardless of node-vs-cell centering */
  double measurementFrame[NRRD_SPACE_DIM_MAX][NRRD_SPACE_DIM_MAX];
                                    /* if spaceDim is non-zero, this may store 
                                       a spaceDim-by-spaceDim matrix which 
                                       transforms vector/matrix coefficients
                                       in the "measurement frame" to those in
                                       the world space described by spaceDim
                                       (and hopefully space).  Coeff [i][j] is
                                       *column* i & *row* j, which is probably
                                       the *transpose* of what you expect.
                                       There are no semantics linking this to
                                       the "kind" of any axis, for a variety
                                       of reasons */
  size_t blockSize;                 /* for nrrdTypeBlock, block byte size */
  double oldMin, oldMax;            /* if non-NaN, and if nrrd is of integral
                                       type, extremal values for the array
                                       BEFORE it was quantized */
  void *ptr;                        /* never read or set by nrrd; use/abuse
                                       as you see fit */

  /* 
  ** Comments.  Read from, and written to, header.
  ** The comment array "cmt" is NOT NULL-terminated.
  ** The number of comments is cmtArr->len.
  */
  char **cmt;
  airArray *cmtArr;

  /*
  ** Key-value pairs.
  */
  char **kvp;
  airArray *kvpArr;
} Nrrd;

Nrrd uses C enums for representing discrete information with more semantic content than a normal integer. The three most important are:

In general, you do not directly set the struct members- you set this information via functions in the Nrrd API. As a matter of convenience, however, it is common and okay to read value directly from the Nrrd struct, although many accessor functions are available as well. The value of looking at the struct definitions above is to understand what information can be represented. There is one NrrdAxis struct for each axis (or dimension) in the dataset, and the only necessary piece of information is the size; everything else is optional meta-information. spacing, thickness, min, and max are all doubles which follow the convention that if no useful value is known, then the value is set to AIR_NAN, which represents Not-A-Number. label and units are standard C char* strings. The center field takes on values from the nrrdCenter enum (above).

In the Nrrd struct, the basic information describing the array are given in data, type, and dim. type takes values from the nrrdType enum (above). Any and all information about the array that is specific to each axis is in the axis array of NrrdAxis structs (note that this is an array of structs, not an array of pointers to structs). The rest of the Nrrd struct is for optional meta-information about the array. Of particular note is the kvp key/value pair array; this becomes the catch-all for other meta-information that you wish to associated with an array in a way that will be saved out to a NRRD file, and recovered upon reading in the file.

2. Input/Output functions, with error reporting

There are four main I/O functions; two functions for reading, and two for writing, and you choose depending on whether you giving a char* filename or a FILE* file pointer:
way to specify I/O Input Output
char* filename nrrdLoad() nrrdSave()
FILE* file pointer nrrdRead() nrrdWrite()
nrrdLoad() and nrrdSave() are more commonly used.

As with most functions in Teem libraries, these functions return an int to signify an error condition or successful completion. Teem uses verbose, detailed, textual error messages in favor of cryptic, integer error codes. The error messages accumulate in a seperate library devoted to error handling, called biff. Thus, handling errors in Nrrd (or any other Teem library) involves making biff calls to get the error messages. Here is a fairly complete/pedantic example of using nrrdLoad and nrrdSave with error handling:

#include <teem/nrrd.h>

void
demoIO(char *filename) {
  char me[]="demoIO", newname[]="foo.nrrd", *err;
  Nrrd *nin;

  /* create a nrrd; at this point this is just an empty container */
  nin = nrrdNew();

  /* read in the nrrd from file */
  if (nrrdLoad(nin, filename, NULL)) {
    err = biffGetDone(NRRD);
    fprintf(stderr, "%s: trouble reading \"%s\":\n%s", me, filename, err);
    free(err);
    return;
  }

  /* say something about the array */
  printf("%s: \"%s\" is a %d-dimensional nrrd of type %d (%s)\n", 
         me, filename, nin->dim, nin->type,
         airEnumStr(nrrdType, nin->type));
  printf("%s: the array contains %d elements, each %d bytes in size\n",
         me, (int)nrrdElementNumber(nin), (int)nrrdElementSize(nin));

  /* write out the nrrd to a different file */
  if (nrrdSave(newname, nin, NULL)) {
    err = biffGetDone(NRRD);
    fprintf(stderr, "%s: trouble writing \"%s\":\n%s", me, newname, err);
    free(err);
    return;
  }

  /* blow away both the Nrrd struct *and* the memory at nin->data
     (nrrdNix() frees the struct but not the data,
     nrrdEmpty() frees the data but not the struct) */
  nrrdNuke(nin);

  return;
}
Things to note here: This code snippet is available as a stand-alone program demoIO.c. When invoked on the hi.png file created on the Other Formats page:
>> demoIO hi.png
demoIO: "hi.png" is a 2-dimensional nrrd of type 2 (unsigned char)
demoIO: the array contains 35 elements, each 1 bytes in size

>> demoIO foo.nrrd
demoIO: "foo.nrrd" is a 2-dimensional nrrd of type 2 (unsigned char)
demoIO: the array contains 35 elements, each 1 bytes in size

>> unu head foo.nrrd
NRRD0001
content: (unsigned char)(???)
type: unsigned char
dimension: 2
sizes: 7 5
encoding: raw

>> rm -f foo.nrrd

>> demoIO foo.nrrd
demoIO: trouble reading "foo.nrrd":
[nrrd] nrrdLoad: fopen("foo.nrrd","rb") failed: No such file or directory

3. Reading a NRRD with a different memory allocator

In some cases you want to read a NRRD in, but you want to do the memory allocation, instead of the nrrd library doing it for you. This is supported in nrrd, but you have to read the nrrd in two steps: the first time reads the nrrd header so that you can figure out how much memory to allocate, and the second time reads in the data (as well as re-reading the header). This function demonstrates this:
Nrrd *
customLoad(char *filename) {
  char me[]="demoIO", *err;
  NrrdIoState *nio;
  Nrrd *nin;
  void *data;
  
  /* create a new nrrd */
  nin = nrrdNew();
  
  /* tell nrrdLoad to only read the header, not the data */
  nio = nrrdIoStateNew();
  nrrdIoStateSet(nio, nrrdIoStateSkipData, AIR_TRUE);
  
  /* read in the nrrd header from file */
  if (nrrdLoad(nin, filename, nio)) {
    err = biffGetDone(NRRD);
    fprintf(stderr, "%s: trouble reading \"%s\" header:\n%s",
            me, filename, err);
    free(err); nio = nrrdIoStateNix(nio);
    return NULL;
  }
  
  /* we're done with the nrrdIoState, this sets it to NULL */
  nio = nrrdIoStateNix(nio);

  /* 1) YOU, the nrrd user, look at things like nin->dim, nin->type
     nin->axis[0].size, nin->axis[1].size, etc in order allocate the data
     for the nrrd.  There are two convenience functions you should use:
     1) nrrdElementNumber(nin) returns the total number of sample values.
     2) nrrdElementSize(nin) returns the number of bytes in each value.
     Make sure that the data is allocated as one single contiguous address
     range, or else nrrd will not operate correctly on the values. */

  /* 2) YOU now set nin->data to the beginning of your allocated memory */
  nin->data = YOUR POINTER HERE;
  
  /* 3) Now load the nrrd again, this time actually reading the data.
     The existing nin->data memory will be used, because nrrdRead
     (called by nrrdLoad) remembers the address and size of incoming
     allocated data, and eventually it will get used, instead of
     nrrd allocating new memory */
  if (nrrdLoad(nin, filename, NULL)) {
    err = biffGetDone(NRRD);
    fprintf(stderr, "%s: trouble reading \"%s\" data:\n%s",
	    me, filename, err);
    free(err);
    return NULL;
  }

  /* return the nrrd.  When your program is done with the nrrd, the right
     way to get rid of it is probably nrrdNix(): this will destroy the
     Nrrd struct and its storage for meta information, but not the underlying
     nrrd->data.  nrrdNuke(), on the other hand, will free(nin->data) */
  return nin;
}

4. Getting data into and out of nrrds

Suppose that you have a 128-by-128-by-64 3-D array of doubles in memory (pointed to by the variable val) that you've generated as part of some computation, and you want to save this array out to disk in NRRD format. Forgetting about error checking, this can be done in four steps:
Nrrd *nval;
...
nval = nrrdNew();
nrrdWrap(nval, val, nrrdTypeDouble, 3, 128, 128, 64);
nrrdSave("val.nrrd", nval, NULL);
nrrdNix(nval);
nrrdWrap() uses var-args based on the dimension of the array (3 in the example above) to know how many integer axis size arguments to expect. Calling nrrdNix() and not nrrdNuke() here is important: we just want to get rid of the struct around the data, not the data itself. One thing to keep in mind is that currently, nrrd has no notion of data ownership. The Nrrd struct doesn't know anything about whether or not its okay to delete the array inside when you called nrrdNuke() on it.

The raster ordering of the data determines whether the last arguments to nrrdWrap() should be (128, 128, 64) or (64, 128, 128). In nrrd, axis-related things are always listed from fast to slow. See the Introduction for an explanation of fast and slow axes.

Adding error checking is not too hard:

Nrrd *nval;
char *err;
...
nval = nrrdNew();
if (nrrdWrap(nval, val, nrrdTypeDouble, 3, 128, 128, 64)
    || nrrdSave("val.nrrd", nval, NULL)) {
  err = biffGetDone(NRRD); 
  ...
}
nrrdNix(nval);
The idiom here is that a long sequence of nrrd calls, all of which return ints, can be chained together as a single boolean expression, so that as soon as one fails, none of the following ones will be called.

If you want nrrd to allocate the memory for you, then you would use nrrdAlloc() and nrrdNuke():

Nrrd *nval;
double *val;
int sx=128, sy=128, sz=64;
...
nval = nrrdNew();
nrrdAlloc(nval, nrrdTypeDouble, 3, sx, sy, sz);
val = (double*)nval->data;
val[10 + sx*(20 + sy*30)] = 42;     /* val[x=10,y=20,z=30] = 42 */
...
nrrdNuke(nval);
Calling nrrdNuke() is appropriate here because nrrd allocated the memory for you in nrrdAlloc(), and nrrdNuke() will free that memory. The "val[10 + sx*(20 + sy*30)] = 42" is just one example of how to access values in a multi-dimensional array, but many others are possible and preferable. Nrrd is so agnostic about multi-dimensional data access that it provides no direct facilities for setting and getting values based on a coordinate vector; there are only minimal facilities for setting/getting values based on a one-dimensional index.

Remember this pairing: nrrdWrap() with nrrdNix(), and nrrdAlloc() with nrrdNuke().

5. Setting/Getting per-axis information

The ability to store meta-information descriptive of each axis of a multi-dimensional array is one of the main differences between "raw" data, and the "nearly raw" data that nrrd supports. The API has a few functions, all starting with nrrdAxisInfo..., which are used to set and get axis information, but there are only two which are commonly used: nrrdAxisInfoGet() and nrrdAxisInfoSet(). The way to communicate which field of the NrrdAxis struct that you wish to set/get is via a C enum, which includes these self-descriptive values: Note the one-to-one correspondence between these enum values and the individual fields in the NrrdAxis struct defined above. For example, if you want to set labels ("x", "y", "z") for each of the three axes in nval:
nrrdAxisInfoSet(nval, nrrdAxisInfoLabel, "x", "y", "z");
Because nrrd has the mentality that "everything is a scalar", you'll need a 4-D array to represent a volume in which each voxel has multiple values associated with it, such as with a 3-D vector field. The "kind" per-axis information is how nrrd provides guidance on representing this situation:
nrrdAxisInfoSet(nvec, nrrdAxisInfoKind,
                nrrdKind3Vector, nrrdKindSpace, nrrdKindSpace, nrrdKindSpace);
nrrdAxisInfoSet(nvec, nrrdAxisInfoLabel, "Vx;Vy;Vz", "x", "y", "z");
Recovering these values from a given nrrd can be done this way if you know exactly what the dimension of the nrrd is:
char *lab0, *lab1, *lab2, *lab3;
int *kind0, *kind1, *kind2, *kind3;
...
nrrdAxisInfoGet(nvec, nrrdAxisInfoLabel, &lab0, &lab1, &lab2, &lab3);
nrrdAxisInfoGet(nvec, nrrdAxisInfoKind, &kind0, &kind1, &kind2, &kind3);
printf("labels were: \"%s\", \"%s\", \"%s\", \"%s\"\n",
       lab0, lab1, lab2, lab3);
printf("kinds were: %s (%d), %s (%d), %s (%d), %s (%d)\n",
       airEnumStr(nrrdKind, kind0), kind0,
       airEnumStr(nrrdKind, kind1), kind1,
       airEnumStr(nrrdKind, kind2), kind2,
       airEnumStr(nrrdKind, kind3), kind3);
It may be easier to use the dimensionally general version of the function:
char *lab[NRRD_DIM_MAX];
int kind[NRRD_DIM_MAX];
int di;
...
nrrdAxisInfoGet_nva(nvec, nrrdAxisInfoLabel, lab);
nrrdAxisInfoGet_nva(nvec, nrrdAxisInfoKind, kind);
for (di=0; didim; di++) {
  printf("axis %d: label = \"%s\", kind = %s (%d)\n",
         di, lab[di], airEnumStr(nrrdKind, kind[di]), kind[di]);
}

Here is a more complete example of setting axis labels, centerings, and spacings:

nrrdAxisInfoSet(nvec, nrrdAxisInfoLabel, "Vx;Vy;Vz", "x", "y", "z");
nrrdAxisInfoSet(nvec, nrrdAxisInfoKind,
                nrrdKind3Vector, nrrdKindSpace, nrrdKindSpace, nrrdKindSpace);
nrrdAxisInfoSet(nvec, nrrdAxisInfoCenter,
                nrrdCenterUnknown,
                nrrdCenterNode, nrrdCenterNode, nrrdCenterNode);
nrrdAxisInfoSet(nvec, nrrdAxisInfoSpacing, AIR_NAN, 1.0, 1.0, 2.0);
nrrdCenterUnknown means "I don't know the centering" or "Centering is moot for this axis". Using AIR_NAN for any double-type per-axis field (spacing, min, or max) similiarly means "don't know", "don't care".

6. Key/Value Pairs

This is the simple but flexible way to store extra fields of information in a Nrrd. These will be preserved exactly when saved to, and read from, a NRRD file. For example, if you want to save some rendering parameters with a floating point rendered image, you might save pairs like ("camera", "4, 5, 0"), ("look-at", "0, 0, 0"), ("U range", "-1, 1"), and so forth. Both the key and the value are just char* strings, but hopefully packing and unpacking between strings and useful values is probably the least of your problems. Here are the calls to add the key/value pairs listed above:
nrrdKeyValueAdd(nrend, "camera", "4, 5, 0");
nrrdKeyValueAdd(nrend, "look-at", "0, 0, 0");
nrrdKeyValueAdd(nrend, "U range", "-1, 1");
To retrieve values:
char *cam, *at;
...
cam = nrrdKeyValueGet(nrend, "camera");
at = nrrdKeyValueGet(nrend, "look-at");
printf("camera = %s, look-at = %s\n", cam, at);
free(cam); free(at);
cam = NULL; at = NULL;
You can also iterate over all key/value pairs:
int ki, nk;
char *key, *val;
...
nk = nrrdKeyValueSize(nrend);
for (ki=0; ki<nk; ki++) {
  nrrdKeyValueIndex(nrend, &key, &val, ki);
  printf("%s = %s\n", key, val);
  free(key); free(val);
  key = NULL; val = NULL;
}

Following the "all strings are strdup()ed" rule of thumb for strings in NRRD, the return from nrrdKeyValueGet() and nrrdKeyValueIndex should be free()d. Individual key/value pairs are erased with nrrdKeyValueErase(), all pairs are erased with nrrdKeyValueClear().

7. Space and orientation

Starting with version 4 of the NRRD format (with magic "NRRD0004"), the Nrrd struct can describe how the array is oriented and positioned relative to some surrounding space. See the relevant section of the NRRD file format spec to see what space and orientation information can be represented. The values of nrrd->space come from an enum (in nrrdEnums.h):
/*
******** nrrdSpace* enum
**
** Identifies the space in which which the origin and direction
** vectors have their coordinates measured.  When a direction is named
** here (like "Left" or "Anterior"), that implies a basis vector that
** points in that direction, along which that coordinate becomes *larger*
** (this is the opposite of MetaIO, for example).
**
** All of these spaces have a well-defined expected dimension, as
** determined by nrrdSpaceDimension(), and setting a nrrd to be in
** such a space, by nrrdSpaceSet(), will automatically set nrrd->spaceDim.
**
** The first six spaces here are PATIENT-ORIENTED spaces, which are
** properly speaking aligned with the patient, and not the scanner
** itself.  But nrrdSpaceScannerXYZ and nrrdSpaceScannerXYZTime are
** DEVICE-ORIENTED spaces, irrespective of the patient, used in a
** previous version of the DICOM standard.  When the two spaces are
** lined up with normal patient orientation in the scanner,
** nrrdSpaceScannerXYZ is the same as nrrdSpaceLeftPosteriorSuperior.
** To quote Part 3 (Information Object Definitions) of the DICOM spec
** (page 275): "If a patient lies parallel to the ground, face-up on
** the table, with his feet-to-head direction same as the
** front-to-back direction of the imaging equipment, the direction of
** the axes of this patient based coordinate system and the equipment
** based coordinate system in previous versions of this Standard will
** coincide."
*/
enum {
  nrrdSpaceUnknown,
  nrrdSpaceRightAnteriorSuperior,     /*  1: NIFTI-1 (right-handed) */
  nrrdSpaceLeftAnteriorSuperior,      /*  2: standard Analyze (left-handed) */
  nrrdSpaceLeftPosteriorSuperior,     /*  3: DICOM 3.0 (right-handed) */
  nrrdSpaceRightAnteriorSuperiorTime, /*  4: */
  nrrdSpaceLeftAnteriorSuperiorTime,  /*  5: */
  nrrdSpaceLeftPosteriorSuperiorTime, /*  6: */
  nrrdSpaceScannerXYZ,                /*  7: ACR/NEMA 2.0 (pre-DICOM 3.0) */
  nrrdSpaceScannerXYZTime,            /*  8: */
  nrrdSpace3DRightHanded,             /*  9: */
  nrrdSpace3DLeftHanded,              /* 10: */
  nrrdSpace3DRightHandedTime,         /* 11: */
  nrrdSpace3DLeftHandedTime,          /* 12: */
  nrrdSpaceLast
};
There are some API functions which facilitate setting and getting this information.

8. Overview of rest of API

The following aims to give a brief description of the important nrrd library calls. See teem/src/nrrd/nrrd.h for a complete list.

Programmers interested in seeing example code that uses the Nrrd API are encouraged to look at the Unrrdu commands that call into Nrrd functions. For example, teem/src/unrrdu/slice.c demonstrates how to call nrrdSlice().

Basic "methods"

These handle the basic operations for creating and destroying nrrds and the data inside
nrrdNew - Create an emtpy nrrd (a container)
nrrdNix - Delete the nrrd struct, but not the data
nrrdEmpty - Free the data, keep the struct
nrrdNuke - Free both the data and the struct
nrrdCopy - Replicate a struct and the data inside
nrrdAlloc - allocate the data segment of a nrrd
nrrdMaybeAlloc - allocate the data segment if the requested size
is different than the current one

Manipulation of per-axis meta-information

nrrdAxisInfoCopy - Copy per-axis info from one nrrd to another
nrrdAxisInfoSet{_nva} - Set one field of axis, for all axes
nrrdAxisInfoGet{_nva} - Get one field of axis, for all axes
nrrdAxisInfoPos - Map from axis "index space" to "world space"
nrrdAxisInfoIdx - Map from axis "world space" to "index space"
nrrdAxisInfoSpacingSet - Set spacing, based on current min/max
nrrdAxisInfoMinMaxSet - Set min and max, based on current spacing

Utility functions

nrrdSanity() should be called on a new Teem build to make sure things are all okay. There is in fact a Teem stand-alone binary called nrrdSanity which is really just a wrapper around nrrdSanity().
nrrdSanity - checks that all compile-time assumptions are true
nrrdContentSet - printf-style setting of the nrrd->content field
nrrdCheck - make sure a given nrrd's fields are valid and consistent
nrrdElementNumber - number of samples in a nrrd
nrrdElementSize - number of bytes in each sample

Comments in nrrd

Comments used to be the only way to extend the nrrd header with other kinds of meta-information, but this is strongly discouraged now that (as of version 1.6.0) we have key/value pairs.
nrrdCommentAdd - add a comment to a nrrd
nrrdCommentClear - clear all comments in a nrrd
nrrdCommentCopy - copy all comments from one nrrd to another

Key/value pairs

Described above.
nrrdKeyValueAdd - add a key/value pair to a nrrd
nrrdKeyValueGet - look up a value for a given key
nrrdKeyValueErase - erase a key/value pair, given the key
nrrdKeyValueClear - clear all key/value pairs in a nrrd
nrrdKeyValueSize - number of key/value pairs in a nrrd
nrrdKeyValueIndex - lookup a key/value pair, indexed by integer

Endianness (byte ordering)

Nrrd is designed so that you don't have to worry about endianness. Whenever the byte ordering of an array matters (when the element size is larger than one byte), and the array is written out with an encoding which exposes endianness (anything besides ASCII), then the endianness is explicitly recorded, in the header. On read, the endianness if flipped automatically (by nrrdRead()) if it is deemed necessary. If, for some twisted reason, you want to change endianness again, this function allows you to do so.
nrrdSwapEndian - reverses the byte-ordering of the data in memory

Getting/Setting values (crude!)

These functions provide a primitive means of setting/getting values in an array of type known only at run-time. Here's an example of their use, to add incr to all the values in a nrrd:
void
demoIncr(Nrrd *nrrd, double incr) {
  double (*lup)(const void *, size_t I);
  double (*ins)(const void *, size_t I, double v);
  double val;
  size_t I, N;
  
  lup = nrrdDLookup[nrrd->type];
  ins = nrrdDInsert[nrrd->type];
  N = nrrdElementNumber(nrrd);
  for (I=0; I<N; I++) {
    val = lup(nrrd->data, I);
    val += incr;
    ins(nrrd->data, I, val);
  }
  return;
}
nrrd{I,F,D}Load[] - dereference a pointer (of indexed type), and cast to int, float, or double
nrrd{I,F,D}Store[] - save a given int, float, or double to the given pointer (which is of indexed type)
nrrd{I,F,D}Lookup[] - lookup a value in a given array (of indexed type), and cast to int, float, or double
nrrd{I,F,D}Insert[] - insert the given int, float, or double of a particular element of a given array (which is of indexed type)

Input from, Output to files

Described above.
nrrdLoad - load a nrrd from a given char* filename
nrrdRead - read a nrrd from a given FILE* file pointer
nrrdSave - save a nrrd to a given char* filename
nrrdWrite - write a nrrd to a given FILE* file pointer

Representing ranges of values

The NrrdRange is a very simple struct who's only job is to represent (you guessed!) a range of scalar values, either as a description of what was seen in a given nrrd, or as input to a function like nrrdQuantize which uses a value range as part of its operation. The introduction of the NrrdRange was the chosen means of making nrrd const-correct.
nrrdRangeNew - create a new NrrdRange based on the given min and max
nrrdRangeNix - delete a NrrdRange
nrrdRangeCopy - allocate and produce a replicate of the given nrrd
nrrdRangeReset - reset a NrrdRange to base state
nrrdRangeSet - Go through the given nrrd and find its min and max.
nrrdRangeSafeSet - Like nrrdRangeSet, but only over-write non-NaN values in the given NrrdRange
nrrdRangeNewSet - combines nrrdRangeNew() and nrrdRangeSet

Simple transforms and warpings of values

nrrdConvert - make a new nrrd which is the result of doing a per-value cast on the old values
nrrdQuantize - reduce the values in a nrrd down to unsigned 8, 16, or 32 bits.a
nrrdUnquantize - try to recover original floating-point values from a quantized nrrd based on the oldMin and oldMax fields.
nrrdHistoEq - perform histogram equalization on the values in a nrrd

Functional mapping of values

In all of the following, the values produced at the output of the mapping can either be scalar (output is same dimension as in input) or multi-scalar, e.g. color (output is one greater dimension than input).
nrrdApply1DLut - send values in a nrrd through a univariate lookup-table
nrrdApply2DLut - send values in a nrrd through a bivariate lookup-table
nrrdApply1DRegMap - send values in a nrrd through a map of linear ramps with uniformly spaced control points
nrrdApply1DIrregMap - send values in a nrrd through a map of linear ramps with irregularly located control points
nrrdApply1DSubstitution - send values through a substitution table

Subset/Superset operations

nrrdSlice - slice an array along some axis at some position (decreases dimension by one)
nrrdSplice - put a given slice into a gived nrrd (logical opposite of nrrdSlice)
nrrdCrop - extract a sub-array of the same dimension
nrrdPad - pad an array out to be bigger (same dimension)
nrrdInset - drop some sub-volume into a larger one (logical opposite of nrrdCrop)

Axis-based value re-ordering

Unlike the functions about axis meta-information (starting with nrrdAxisInfo...), the functions relating to transforms on the scan-line ordering of the samples themselves all start with nrrdAxes.... This may not have been the wisest choice, but its here now.
nrrdAxesPermute - re-order axes in the scan-line ordering of samples
nrrdAxesSwap - re-order two specific axes (special case of nrrdAxesPermute)
nrrdShuffle - re-order slices along some axis
nrrdFlip - changes ordering of slices along some axis (special case of nrrdShuffle)
nrrdJoin - join multiple input nrrds along some existing axis or a new one
nrrdReshape - (like Matlab's command) impose some new raster dimensions on an existing array
nrrdAxesInsert - insert a new stub (size=1) axis amongst some existing ones
nrrdAxesDelete - remove a stub axis from a nrrd
nrrdAxesSplit - split one axis into two adjacent axes (a fast and a slow)
nrrdAxesMerge - Join two adjacent axes into a single axis
nrrdTile2D - Tile the slices along one axis into two other axes (makes a mosaic image)
nrrdUntile2D - Undoes the action of nrrdTile2D

"Measuring" an array

This is one of the more powerful function calls in nrrd: it allows you to do axis-aligned maximum intensity projections, find the L2-norm of each of a volume of vectors, find the median/mean/mode value of each scanline of a multi-dimensional scatterplot.
nrrdProject - reduce all samples along scanlines (along the given axis) to a single scalar, according to the given measure.

All things histogram-related

Because nrrd grew out of ideas on array representation that I had when writing my Master's thesis, histograms have always been a key part.
nrrdHisto - generate a histogram of the values in a nrrd
nrrdHistoDraw - draws a uni-variate histogram in a helpful way.
nrrdHistoAxis - replace every scanline with its histogram (takes a while to wrap head around this)
nrrdHistoJoint - create multi-dimensional joint histogram of a list of nrrds.

Arithmetic operations on one or more nrrds

nrrdArithGamma - "gamma correct" all values in a nrrd
nrrdArithUnaryOp - Send all values in a nrrd through some unary function, e.g. sin(), log(), abs(), etc.
nrrdArithBinaryOp - do some binary function (takes two arguments) on two nrrds, or on a nrrd and a constant
nrrdArithTernaryOp - so some ternary function (takes three arguments) on nrrds and constants (any possibility barring three constants)

Filtering and Resampling

The median filtering is cheap and slow. The spatial resampling, on the other hand, is a ridiculously complex and multi-purpose function, but with an aim towards fast computation. It allows cropping and padding as part of resampling, using different kernels on different axes, resampling some axes while leaving others untouched, drawing from the very large vocabulary of kernels that nrrd is compiled with. See nrrd.h and resampleNrrd.c for details, and look at teem/src/unrrdu/resample.c for an example of a simplified interface to the resampler.
nrrdCheapMedian - perform simple histogram-based median filtering in 1-D, 2-D or 3-D
nrrdSpatialResample - perform filtered up-sampling or down-sampling with arbitrary (seperable) kernels
nrrdResampleExecute - re-implementation of nrrdSpatialResample to allow fast resampling of multiple images

Connected components

These are pretty slow and stupid for the time being. They will be optimized later, but the API should stay put.
nrrdCCFind - find connected components in 1-D, 2-D or 3-D
nrrdCCMerge - merge some components into others, based on a variety of criteria
nrrdCCSettle - assign set of lowest-valued possible component IDs