1% 2% Copyright 1993 Peter Neelin, McConnell Brain Imaging Centre, 3% Montreal Neurological Institute, McGill University. 4% Permission to use, copy, modify, and distribute this 5% software and its documentation for any purpose and without 6% fee is hereby granted, provided that the above copyright 7% notice appear in all copies. The author and McGill University 8% make no representations about the suitability of this 9% software for any purpose. It is provided "as is" without 10% express or implied warranty. 11% 12\documentclass{article} 13\title{MINC Programmer's Guide} 14\author{Peter Neelin} 15\date{May 14, 1993} 16\textwidth 6.0in 17\oddsidemargin 0.125in 18\textheight 8.5in 19\topmargin -0.75in 20 21\begin{document} 22 23\maketitle 24 25\tableofcontents 26 27\clearpage 28 29\section{Introduction} 30 31The MINC file format (Medical Image NetCDF) is based on the NetCDF 32file format (Network Common Data Form) distributed by the Unidata 33Program Center. NetCDF provides a software interface for storing 34named, multi-dimensional variables in files in a machine-independent 35way. This interface removes applications from the concerns of 36portability and file structure and encourages a self-describing form 37of data. 38 39Each NetCDF multi-dimensional variable in a file is described by a 40name, by its dimensions and by attributes. For example, an image 41stored in a file might be stored as byte data in a variable called 42``\verb+image+'', with dimensions ``\verb+x+'' and ``\verb+y+'' (each 43of length 256) and with an attribute called ``\verb+long_name+'' which 44is a string describing the content of the image. Many variables can be 45stored in one file and each variable can have many attributes. 46Dimensions exist independently of variables and can subscript more 47than one variable. 48 49MINC provides three things on top of the NetCDF interface. It provides 50a standard for dimension, variable and attribute names suitable for 51medical imaging, it provides some convenience functions to complement 52the NetCDF interface (not specific to the MINC conventions) and it 53provides convenience functions for using MINC files. 54 55\section{An Introduction to NetCDF} 56 57(For a complete description, see the ``NetCDF User's Guide''). 58 59\subsection{The NetCDF file} 60 61It is useful to look at an example file while considering the NetCDF 62interface. Fortunately, the NetCDF package provides utilities (ncdump 63and ncgen) for converting the binary NetCDF files to an ascii format 64call CDL. A simple NetCDF file, converted to CDL notation by ncdump, 65is given below: 66 67\begin{verbatim} 68netcdf test { 69dimensions: 70 ycoord = 3 ; 71 xcoord = 4 ; 72 73variables: 74 double image(ycoord, xcoord) ; 75 image:long_name = "My favorite tiny image" ; 76 double xcoord(xcoord) ; 77 78data: 79 80 image = 81 1, 2, 3, 4, 82 5, 6, 7, 8, 83 9, 10, 11, 12 ; 84 85 xcoord = 100, 200, 300, 400 ; 86} 87\end{verbatim} 88 89The sample file stores a 3 by 4 image of double precision values. The 90first thing defined are the dimensions : \verb+xcoord+ and 91\verb+ycoord+. Dimensions can represent physical dimensions like x 92coordinate, y coordinate etc., or they can represent abstract things 93like lookup-table index. Each dimension has a name and a length and 94when joined with other dimensions defines the shape of a variable --- 95the variable image is subscripted by \verb+ycoord+ and \verb+xcoord+. 96Dimensions can also be used across variables, relating them to each 97other. For example, if the file contained another image also 98subscripted by \verb+ycoord+ and \verb+xcoord+, we would have the 99important information that the two variables were sampled on the same 100grid. Also, coordinate systems can be defined by creating variables 101by the same name as the dimension, like \verb+xcoord+ in the example 102above, giving the x coordinate of each point in the image. 103 104Variables are the next thing defined in the cdl file. Each variable 105has a name, data type and a shape specified by a list of dimensions 106(up to a maximum of \verb+MAX_VAR_DIMS+ = 32 dimensions per variable). 107The data types are \verb+NC_CHAR+, \verb+NC_BYTE+, \verb+NC_SHORT+, 108\verb+NC_INT+, \verb+NC_FLOAT+ and \verb+NC_DOUBLE+. Information 109about each variable is stored in attributes. The attribute 110``\verb+long_name+'' gives a character string describing the variable 111``\verb+image+''. Attributes are either scalars or vectors of one of 112the six types listed above (a character string is a vector of type 113\verb+NC_CHAR+). 114 115\subsection{Programming with NetCDF} 116 117Programming with NetCDF can be quite simple. The file listed above was 118produced by the following program: 119 120\begin{verbatim} 121#include <netcdf.h> 122 123#define THE_NAME "My favorite tiny image" 124static double vals[][4]={ 125 1.0, 2.0, 3.0, 4.0, 126 5.0, 6.0, 7.0, 8.0, 127 9.0,10.0,11.0,12.0 128}; 129static int ysize=sizeof(vals)/sizeof(vals[0]); 130static int xsize=sizeof(vals[0])/sizeof(vals[0][0]); 131 132static double xcoord[]={100.,200.,300.,400.}; 133 134main() 135{ 136 int cdf, img, xvar; 137 int dim[MAX_VAR_DIMS]; 138 long count[MAX_VAR_DIMS], start[MAX_VAR_DIMS]; 139 140 /* Create the file */ 141 cdf=nccreate("test.cdf",NC_CLOBBER); 142 143 /* Define the dimensions */ 144 dim[0]=ncdimdef(cdf, "ycoord", ysize); 145 dim[1]=ncdimdef(cdf, "xcoord", xsize); 146 147 /* Define the variables */ 148 img=ncvardef(cdf, "image", NC_DOUBLE, 2, dim); 149 xvar=ncvardef(cdf,"xcoord", NC_DOUBLE, 1, &dim[1]); 150 151 /* Add an attribute */ 152 ncattput(cdf, img, "long_name", NC_CHAR, strlen(THE_NAME)+1, THE_NAME); 153 154 /* End definition mode */ 155 ncendef(cdf); 156 157 /* Write the variable values */ 158 start[0]=start[1]=0; 159 count[0]=ysize; count[1]=xsize; 160 ncvarput(cdf, img, start, count, vals); 161 ncvarput(cdf, xvar, &start[1], &count[1], xcoord); 162 ncclose(cdf); 163} 164\end{verbatim} 165 166The first executable line of the program creates a new NetCDF file. An 167open file is either in ``define'' mode or in ``data'' mode. In define 168mode, dimensions, variables and attributes can be defined, but data 169cannot be written to or read from variables. In data mode, variable 170values can be written or read, but no changes to dimensions or 171variables can be made and attributes can only be written if they exist 172already and will not get larger with the write. Newly created files 173are automatically in define mode. 174 175The lines following the call to nccreate define the dimensions and 176variables in the file. Notice that the NetCDF file, dimensions and 177variables are all identified by an integer returned when they are 178created. These id's are subsequently used to refer to each object. The 179attribute ``\verb+long_name+'' for the image variable is identified 180only by its name. 181 182Once everything is defined, ncendef puts the file into data mode and 183values are written. The values to write are defined by a vector of 184starting indices and a vector of the number of values to write in each 185dimension. This defines a multi-dimensional rectangle within the 186variable called a hyperslab. In the C interface, the first element of 187the vector refers to the slowest varying index of the variable, so in 188this example, the array vals has the \verb+xcoord+ varying fastest. In 189the FORTRAN interface, the convention has the first subscript varying 190fastest. These conventions follow the language conventions for 191multi-dimensional arrays. 192 193\section{The MINC format} 194 195It is possible to build MINC format files using only NetCDF function 196calls, however a C include file is provided to facilitate (and help 197ensure) adherence to the standard. This file defines useful constants, 198standard dimension, variable and attribute names and some attribute 199values. It also declares the functions defined in a library of minc 200convenience functions, designed to make an application programmer's 201life easier. 202 203\subsection{The MINC standard} 204 205Various requirements for file formats have been put forward. One such 206list is as follows: A protocol should be: 1) simple, 2) self 207describing, 3) maintainable, 4) extensible, 5) N dimensional, and 6) 208have a universal data structure. The NetCDF format meets all of these 209requirements, suggesting that it is a good place to start. I would, 210however, add some more requirements to the list. Implied in the above 211list is the requirement that there be a standard for accessing data 212(how do I get the patient name) --- this is not provided by NetCDF. 213Furthermore, a useful format should come with a software interface 214that makes it easy to use, particularly in a development environment. 215Finally, a format that stores many associated pieces of information 216should also provide some data organization. 217 218The MINC format attempts to add these things to the NetCDF format. 219 220\subsubsection{MINC variable types} 221 222Medical imaging tends to produce files with a large amount of 223ancillary data (patient information, image information, acquisition 224information, etc.). To organise this information in a useful fashion, 225MINC uses variables to group together related attributes. The variable 226itself may or may not contain useful data. For example, the variable 227\verb+MIimage+ contains the image data and has attributes relevant to this 228data. The variable \verb+MIpatient+ has no relevant variable data, but 229serves to group together all attributes describing the patient (name, 230birthdate, etc.). This sort of variable is called a group variable. 231 232Variables that correspond to dimensions are called dimension variables 233and describe the coordinate system corresponding to the dimension. An 234example is MIxspace --- both a dimension and a variable describing the 235x coordinate of other variables. 236 237The NetCDF conventions allow for these dimension variables to specify 238the coordinate at each point, but there is nothing to describe the 239width of the sample at that point. MINC provides the convention of 240dimension width variables, e.g. \verb+MIxspace_width+, to give this 241information. 242 243Finally, it is possible to have attributes that vary over some of the 244dimensions of the variable. For example, if we have a volume of image 245data, varying over \verb+MIxspace+, \verb+MIyspace+ and 246\verb+MIzspace+, we may want an attribute giving the maximum value of 247the each image, varying over \verb+MIzspace+. To achieve this we use a 248variable, called a variable attribute, pointed to by an attribute of 249the image variable. 250 251Thus MINC introduces a number of types of variables: group variables, 252dimension variables, dimension width variables and variable 253attributes. 254 255\subsubsection{Data organization} 256 257MINC attempts to provide some level of data organization through a 258hierarchy of group variables. As mentioned above, attributes are 259grouped according to type in group variables. Each group variable can 260have an \verb+MIparent+ and an \verb+MIchildren+ attribute --- the 261former specifying the name of another variable that is above this one 262in the hierarchy, the latter specifying a newline-separated list of 263variables that come below this one in the hierarchy. At the root of 264the hierarchy is the \verb+MIrootvariable+ variable, with no parent. 265Although it is not necessary to make use of this structure, it can 266provide a mechanism for ordering large amounts of information. 267 268\subsubsection{MINC dimension, variable and attribute names} 269 270The NetCDF format says nothing about variable and dimension naming 271conventions and little about attribute names. It does provide a few 272standards, such as the attribute ``\verb+long_name+'' for describing a 273variable, which have been adopted by the MINC standard. MINC defines a 274set of standard names for commonly used entities and the include file 275defines constants specifying these names. These are described at 276length in the MINC reference manual. The most interesting of these is 277\verb+MIimage+, the name of the variable used for storing the actual image 278data in the file. 279 280\subsubsection{Image dimensions} 281 282The MINC standard gives some special status to the concept of an 283image. There is nothing inherent in NetCDF that suggests any special 284status for particular dimensions, but it can be convenient to place 285limitations on what can vary over which dimensions in an imaging 286context. For example, the requirement that the variables that specify 287how to rescale images (see later section on pixel values) not vary 288with image dimensions means that we can treat the image as a simple 289unit. In the simplest case, the image dimensions are simply the two 290fastest varying dimensions of the \verb+MIimage+ variable. 291 292It can also be helpful to allow for vector fields --- images or image 293volumes that have a vector of values at each point. A simple example 294of a vector field is an RGB image. At each point in space, there are 295three values: red, green and blue. The dimension 296\verb+MIvector_dimension+ is used for the components of the vector and 297it should be the fastest varying dimension in the \verb+MIimage+ variable. If 298it is present, then the three fastest varying dimensions of \verb+MIimage+ 299are the image dimensions. 300 301\subsubsection{MINC coordinate system} 302 303The MINC standard defines how spatial coordinates should be oriented 304relative to patients. Files are free to have data stored in the 305desired direction, but positive world coordinates are given a definite 306meaning in the medical imaging context. The standard is that the 307positive x axis points from the patient's left to right, the positive 308y axis points from posterior to anterior and the positive z axis 309points from inferior to superior. 310 311The conversion of element index to world coordinates is done using the 312dimension variable attributes \verb+MIdirection_cosines+, 313\verb+MIstep+ and \verb+MIstart+. If the direction cosines are 314${\bf c}=(c_x, c_y, c_z)$, then the vector between adjacent elements 315along an axis is $step\times {\bf c}$. If $start(i)$ and 316${\bf c}(i)$ are the \verb+MIstart+ and 317\verb+MIdirection_cosines+ attributes for dimension $i$ (one of 318\verb+MIxspace+, \verb+MIyspace+ and \verb+MIzspace+), 319then the first element of the image variable is at world coordinate 320$ \sum_i start(i) {\bf c}(i) $. 321 322If the direction cosines are not present, then they are 323assumed to be $(1,0,0)$ for \verb+MIxspace+, $(0,1,0)$ for 324\verb+MIyspace+ and $(0,0,1)$ for \verb+MIzspace+. Direction cosines are 325unit vectors and should be normalized. As well, the step attribute 326should carry the information about axis flipping (negative or 327positive) rather than the direction cosine. 328 329\subsubsection{Pixel values and real values} 330 331In medical imaging, pixel values are frequently stored as bytes or 332shorts, but there is a generally a real value associated with each 333pixel as well. This real value is obtained by a scale factor and 334offset associated with each image or image volume. The MINC standard 335indicates how pixel values should be interpreted. 336 337Image data in the \verb+MIimage+ variable can be stored as bytes, shorts, 338ints (32-bit), floats or doubles. NetCDF conventions use the attributes 339\verb+MIvalid_range+ or \verb+MIvalid_max+ and \verb+MIvalid_min+ to 340indicate the range of values that can be found in the variable. For 341short values, for example, we might have a valid range of 0 to 32000. 342To convert these integers to real values, we could use a scale and 343offset. However, these values would have to change if the data where 344converted to bytes in the range 23 to 228. If we specify an image 345maximum and minimum to which \verb+MIvalid_max+ and \verb+MIvalid_min+ 346should be mapped by an appropriate scale and offset, then we can 347convert type and valid range without having to change the real maximum 348and minimum. To allow the maximum dynamic range in an image, we use 349the variables \verb+MIimagemax+ and \verb+MIimagemin+ to store the 350real maximum and minimum --- these can vary over any of the non-image 351dimensions of \verb+MIimage+. 352 353\subsection{General convenience functions} 354 355MINC provides a number of convenience functions that have nothing to 356do with medical imaging, but that make the use of NetCDF files a 357little easier. One of the drawbacks of the NetCDF format is that data 358can come in any form (byte, short, int, float, double) and the 359calling program must handle the general case. Rather than restrict 360this, MINC provides functions to convert types. 361 362The first set of convenience functions are for type conversion. A list 363follows : 364\begin{itemize} 365 \item {\bf \verb+miattget+} - reads an attribute vector, specifying 366 the numeric type desired and the maximum number of values to read. 367 \item {\bf \verb+miattget1+} - reads one attribute value of the 368 specified type. 369 \item {\bf \verb+miattgetstr+} - read a character attribute of a specified 370 maximum length. 371 \item {\bf \verb+miattputdbl+} - write a double precision attribute. 372 \item {\bf \verb+miattputstr+} - write a string attribute. 373 \item {\bf \verb+mivarget+} - get a hyperslab of values of the 374 specified type. 375 \item {\bf \verb+mivarget1+} - get a single value of the specified type. 376 \item {\bf \verb+mivarput+} - put a hyperslab of values of the 377 specified type. 378 \item {\bf \verb+mivarput1+} - put a single value of the specified type. 379\end{itemize} 380 381Next we have some functions for handling coordinate vectors : 382\begin{itemize} 383 \item {\bf \verb+miset_coords+} - set a vector of coordinates to a 384 single value. 385 \item {\bf \verb+mitranslate_coords+} - translate the coordinates for one 386 variable to a vector for subscripting another variable. 387\end{itemize} 388 389Finally, there are functions for dealing with variables as groups of 390attributes, making it easier to modify a file while keeping ancillary 391information : 392\begin{itemize} 393 \item {\bf \verb+micopy_all_atts+} - copy all of the attributes of 394 one variable to another (possibly across files). 395 \item {\bf \verb+micopy_var_def+} - copy a variable definition (including 396 attributes) from one file to another. 397 \item {\bf \verb+micopy_var_vals+} - copy a variable's values from 398 one variable to another (possibly across files). 399 \item {\bf \verb+micopy_all_var_defs+} - copy all variable 400 definitions from one file to another, excluding a list of variables. 401 \item {\bf \verb+micopy_all_var_vals+} - copy all variable values 402 from one file to another, excluding a list of variables. 403\end{itemize} 404 405\subsection{MINC specific convenience functions} 406 407A few routines are provided to deal with some of the minc structures. 408\verb+miattput_pointer+ and \verb+miattget_pointer+ put/get a pointer to a 409variable attribute. \verb+miadd_child+ helps maintain the hierarchy of 410variables by handling the \verb+MIparent+ and \verb+MIchildren+ 411attributes of two variables. Finally \verb+micreate_std_variable+ and 412\verb+micreate_group_variable+ create some of the standard variables 413and fill in a few of the default attributes. 414 415\subsection{Image conversion variables} 416 417One of the requirements for file formats mentioned earlier was 418a software interface to make the interface easy to use. The biggest 419difficulty in using a flexible format is that the application must 420handle many possibilities. Where images are concerned, this means 421various data types and scale factors, and images of differing sizes. 422The image conversion variable functions of MINC attempt to remove this 423complication for the programmer. 424 425An image conversion variable (icv) is essentially a specification of what 426the program wants images to look like, in type, scale and dimension. 427When an MINC image is read through an icv, it is converted for the 428calling program to a standard format regardless of how data is stored 429in the file. 430 431There are two categories of conversion: Type and range conversions 432change the datatype (and sign) of image values and optionally scale 433them for proper normalization. Dimension conversions allow programs to 434specify image dimension size and image axis orientation (should 435\verb+MIxspace+ coordinates be increasing or decreasing? should the 436patient's left side appear on the left or right of the image?). 437 438\subsubsection{ICV routines} 439 440Accessing a file through an icv is a straight-forward process. 441Create the icv with \verb+miicv_create+, set properties 442(like desired datatype) with the \verb+miicv_set+ routines, attach the 443icv to a NetCDF 444variable with \verb+miicv_attach+ and access the data with 445\verb+miicv_get+ or \verb+miicv_put+. The icv can be detached from a 446NetCDF variable with \verb+miicv_detach+ and can be freed with 447\verb+miicv_free+. 448 449Icv properties are strings, integers, long integers or doubles. For 450example, \verb+MI_ICV_SIGN+ (the sign of variable values) is a string, 451while \verb+MI_ICV_IMAGE_MAX+ (image maximum) is a double precision 452value. Four functions --- \verb+miicv_setint+, \verb+miicv_setlong+, 453\verb+miicv_setdbl+ and \verb+miicv_setstr+ --- 454are provided to simplify the setting of property values. Programs can 455inquire about property values with \verb+miicv_inqint+, 456\verb+miicv_inqlong+, \verb+miicv_inqdbl+ and \verb+miicv_inqstr+. 457 458\subsubsection{Type and range conversion} 459 460Pixel values are converted for type and sign by specifying values for 461the properties \verb+MI_ICV_TYPE+ and \verb+MI_ICV_SIGN+ (they default 462to \verb+NC_SHORT+ and \verb+MI_SIGNED+). Values can also be converted 463for valid range and for normalization. These conversions are enabled 464by setting \verb+MI_ICV_DO_RANGE+ to \verb+TRUE+ (the default). 465 466If \verb+MI_ICV_DO_NORM+ is \verb+FALSE+ (the default) then only 467conversions for valid range are made. This means that if the input 468file has shorts in the range 0 to 4095, then they can be converted to 469bytes in the range 64 to 248 (for example). The real image maximum and 470minimum (\verb+MIimagemax+ and \verb+MIimagemin+) are ignored. The 471valid range is specified by the properties \verb+MI_ICV_VALID_MAX+ and 472\verb+MI_ICV_VALID_MIN+, which default to the legal range for the type 473and sign. 474 475We may want to scale values so that they are normalized either to all 476values in the \verb+MIimage+ variable or to some user-defined range. 477To do normalization, set \verb+MI_ICV_DO_NORM+ to \verb+TRUE+. Setting 478\verb+MI_ICV_USER_NORM+ to \verb+FALSE+ (the default) causes normalization to 479the real maximum and minimum of the variable (the maximum of 480\verb+MIimagemax+ and the minimum of \verb+MIimagemin+). If 481\verb+MI_ICV_USER_NORM+ is true then the values of \verb+MI_ICV_IMAGE_MAX+ 482and \verb+MI_ICV_IMAGE_MIN+ are used (defaulting to 1.0 and 0.0). 483 484When either \verb+MI_ICV_TYPE+ or the file type is floating-point, 485then the conversion to and from real values is always done using the 486real image maximum and minimum information. If the internal type is 487integer and \verb+MI_ICV_DO_NORM+ is \verb+FALSE+, then the rescaling 488is done so that the slice maximum maps to the valid range of the 489internal values. 490 491Note that when converting to integer types, values are rounded to the 492nearest integer and limited to be within the legal range for the data 493type. 494 495The above transformations are simple enough, but the use of 496floating-point values adds to the complexity, since in general we do 497not want to rescale these values to get the real values. The various 498possibilities are described in greater detail below. 499 500\subsubsection{The details of pixel value conversion} 501 502The easiest way to think about the rescaling is through four ranges 503(maximum-minimum pairs). In the file variable, values have a 504valid range \verb+var_vrange+ and these correspond to real values 505\verb+var_imgrange+. The user/application wants to convert real values 506\verb+usr_imgrange+ to a useful valid range \verb+usr_vrange+. From 507\verb+var_vrange+, \verb+var_imgrange+, \verb+usr_imgrange+ and 508\verb+usr_vrange+, we can determine a scale and offset for converting 509pixel values: Input values are scaled to real values by 510\verb+var_vrange+ to \verb+var_imgrange+ and then scaled again to user 511values by \verb+usr_imgrange+ to \verb+usr_vrange+. 512 513If either of the \verb+vrange+ variables are not specified, they default to 514maximum possible range for integer types. For floating 515point types, \verb+usr_vrange+ is set equal to \verb+usr_imgrange+ 516so that no conversion of real values is done. 517 518If normalization is not being done, then for integer types 519\verb+var_imgrange+ and \verb+usr_imgrange+ are set to [0,1] (scale 520down to [0,1] and scale up again). When normalizibng, 521\verb+usr_imgrange+ is set to either the full range of the variable 522([0,1] if not found) or the user's requested range. If the variable 523values are floating point, then \verb+var_imgrange+ is set to 524\verb+var_vrange+ (no scaling to real values), otherwise 525\verb+var_imgrange+ is read for each image (again, [0,1] if not 526found). 527 528What this means for reading and writing images is discussed below. 529 530\subsubsection{Reading with pixel conversion} 531 532When reading into internal floating point values, normalization has no 533effect. When reading integers without normalization, each image is 534scaled to full range. With normalization they are scaled to the 535specified range and slices can be compared. 536 537When the input file is missing either 538\verb+MIimagemax+/\verb+MIimagemin+ (\verb+var_imgrange+ information) 539or \verb+MIvalid_range+, the routines try to provide sensible 540defaults, but funny things can still happen. The biggest problem is 541the absence of \verb+MIvalid_range+ if the defaults are not correct 542(full range for integer values and [0,1] for floating point). When 543converting floating point values to an integer type, there will be 544overflows if values are outside the range [0,1]. 545 546\subsubsection{Writing with pixel conversion} 547 548The conversion routines can be used for writing values. This can be 549useful for data compression --- e.g. converting internal floats to 550byte values in the file, or converting internal shorts to bytes. When 551doing this with normalization (to rescale bytes to the slice maximum, 552for example) it is important to write the slice maximum and minimum in 553\verb+MIimagemax+ and \verb+MIimagemin+ before writing the slice. 554 555The other concern is that \verb+MIvalid_range+ or \verb+MIvalid_max+ 556and \verb+MIvalid_min+ be written properly (especially if the defaults 557are not correct). When writing floating point values, 558\verb+MIvalid_range+ should be set to the full range of values in the 559variable. In this case, the attribute does not have to be set 560correctly before writing the variable, but if it exists, the values 561should be reasonable (maximum greater than minimum and values not 562likely to cause overflow). These will be set automatically if the 563routine \verb+micreate_std_variable+ is used with 564\verb+NC_FILL+ mode on (the default). 565 566\subsubsection{Example: Reading values} 567 568Read an image without normalization: 569\begin{verbatim} 570 /* Create the icv */ 571 icv=miicv_create(); 572 (void) miicv_setint(icv, MI_ICV_TYPE, NC_SHORT); 573 (void) miicv_setstr(icv, MI_ICV_SIGN, MI_UNSIGNED); 574 (void) miicv_setint(icv, MI_ICV_VALID_MAX, 32000); 575 (void) miicv_setint(icv, MI_ICV_VALID_MIN, 0); 576 577 /* Open the file, attach the image variable */ 578 cdfid=ncopen(filename, NC_NOWRITE); 579 580 /* Attach image variable */ 581 img=ncvarid(cdfid, MIimage); 582 (void) miicv_attach(icv, cdfid, img); 583 584 /* Get the data - we assume that coord and count are set properly */ 585 (void) miicv_get(icv, coord, count, image); 586 587 /* Close the file and free the icv */ 588 (void) ncclose(cdfid); 589 (void) miicv_free(icv); 590\end{verbatim} 591 592Read an integer image with normalization: 593\begin{verbatim} 594 /* Create the icv */ 595 icv=miicv_create(); 596 (void) miicv_setint(icv, MI_ICV_TYPE, NC_SHORT); 597 (void) miicv_setstr(icv, MI_ICV_SIGN, MI_UNSIGNED); 598 (void) miicv_setint(icv, MI_ICV_VALID_MAX, 32000); 599 (void) miicv_setint(icv, MI_ICV_VALID_MIN, 0); 600 (void) miicv_setint(icv, MI_ICV_DO_NORM, TRUE); 601 (void) miicv_setint(icv, MI_ICV_USER_NORM, TRUE); 602 (void) miicv_setdbl(icv, MI_ICV_IMAGE_MAX, 1.83); 603 (void) miicv_setdbl(icv, MI_ICV_IMAGE_MIN, -0.57); 604 ... 605\end{verbatim} 606 607Read a floating point image : 608\begin{verbatim} 609 /* Create the icv. We don't have to set MI_ICV_USER_NORM to TRUE, 610 but doing so ensures that the conversion is done properly 611 without looking at file values (the defaults for 612 MI_ICV_IMAGE_MAX and MI_ICV_IMAGE_MIN are 1 and 0) */ 613 icv=miicv_create(); 614 (void) miicv_setint(icv, MI_ICV_TYPE, NC_FLOAT); 615 (void) miicv_setint(icv, MI_ICV_DO_NORM, TRUE); 616 (void) miicv_setint(icv, MI_ICV_USER_NORM, TRUE); 617 ... 618\end{verbatim} 619 620\subsubsection{Example: Writing values} 621 622Writing from floating point to byte values : 623 624\begin{verbatim} 625 /* Create the icv */ 626 icv=miicv_create(); 627 (void) miicv_setint(icv, MI_ICV_TYPE, NC_FLOAT); 628 (void) miicv_setint(icv, MI_ICV_DO_NORM, TRUE); 629 630 /* Create the file */ 631 cdf=nccreate(filename, NC_CLOBBER); 632 633 /* Define the dimensions */ 634 dim[0]=ncdimdef(cdf, MIyspace, ysize); 635 dim[1]=ncdimdef(cdf, MIxspace, xsize); 636 637 /* Define the variables */ 638 img=micreate_std_variable(cdf, MIimage, NC_BYTE, 2, dim); 639 (void) miattputstr(cdf, img, MIsigntype, MI_UNSIGNED); 640 vrange[0]=0; vrange[1]=200; 641 (void) ncattput(cdf, img, MIvalid_range, NC_DOUBLE, 2, vrange); 642 max=micreate_std_variable(cdf, MIimagemax, NC_DOUBLE, 0, NULL); 643 min=micreate_std_variable(cdf, MIimagemin, NC_DOUBLE, 0, NULL); 644 645 /* End definition mode */ 646 ncendef(cdf); 647 648 /* Attach image variable */ 649 (void) miicv_attach(icv, cdf, img); 650 651 /* Write the image max and min */ 652 ncvarput1(cdf, max, NULL, &image_maximum); 653 ncvarput1(cdf, min, NULL, &image_minimum); 654 655 /* Write the image */ 656 start[0]=start[1]=0; 657 count[0]=ysize; count[1]=xsize; 658 miicv_put(icv, start, count, vals); 659 660 /* Close the file and free the icv */ 661 (void) ncclose(cdf); 662 (void) miicv_free(icv); 663\end{verbatim} 664 665If we were writing a floating point image, the only difference (apart 666from changing \verb+NC_BYTE+ to \verb+NC_FLOAT+) would be that we 667would rewrite \verb+MIvalid_range+ at the end of the file with the 668full range of floating point values. 669 670\subsubsection{Dimension conversion} 671 672One of the problems of arbitrary dimensioned images is that it becomes 673necessary for software to handle the general case. It is easier to write 674application software if it is known in advance that all images will 675have a specific size (e.g. $256\times 256$) and a specific orientation 676(e.g. the first pixel is at the patient's anterior, right side). 677 678By setting the icv property \verb+MI_ICV_DO_DIM_CONV+ to \verb+TRUE+ 679these conversions can be done automatically. The orientation of 680spatial axes is determined by the properties \verb+MI_ICV_XDIM_DIR+, 681\verb+MI_ICV_YDIM_DIR+ and \verb+MI_ICV_ZDIM_DIR+. These affect any 682image dimensions that are \verb+MI?space+ or \verb+MI?frequency+ where 683\verb+?+ corresponds to \verb+x+, \verb+y+ or \verb+z+. These 684properties can have values \verb+MI_ICV_POSITIVE+, 685\verb+MI_ICV_NEGATIVE+ or \verb+MI_ICV_ANYDIR+. The last of these will 686prevent flipping of the dimension. The first two will flip the 687dimension if necessary so that the attribute \verb+MIstep+ of the 688dimension variable will have the correct sign. 689 690The two image dimensions are referred to as dimensions A and B. 691Dimension A is the fastest varying dimension of the two. Setting 692properties \verb+MI_ICV_ADIM_SIZE+ and \verb+MI_ICV_BDIM_SIZE+ specify 693the desired size for the image dimension. Dimensions are resized so 694that the file image will fit entirely in the calling program's image, 695and is centred in the image. The size \verb+MI_ICV_ANYSIZE+ allows 696one of the dimensions to have a variable size. If property 697\verb+MI_ICV_KEEP_ASPECT+ is set to \verb+TRUE+, then the two 698dimensions are rescaled by the same amount. It is possible to inquire 699about the new step and start, corresponding to attributes 700\verb+MIstep+ and \verb+MIstart+ (where pixel position = ipixel*step + 701start, with ipixel counting from zero). The properties 702\verb+MI_ICV_?DIM_STEP+ and \verb+MI_ICV_?DIM_START+ (\verb+?+ = 703\verb+A+ or \verb+B+) are set automatically and can be inquired but 704not set. 705 706Although vector images are allowed, many applications would rather 707only deal with scalar images (one intensity value at each point). 708Setting \verb+MI_ICV_DO_SCALAR+ to \verb+TRUE+ (the default) will 709cause vector images to be converted to scalar images by averaging the 710components. (Thus, RGB images are automatically converted to 711gray-scale images in this simple way). 712 713It can sometimes be useful for a program to perform dimension 714conversions on three (or perhaps more) dimensions, not just the two 715standard image dimensions. To perform dimension flipping and/or 716resizing on dimensions beyond the usual two, the property 717\verb+MI_ICV_NUM_IMGDIMS+ can be set to an integer value between 718one and \verb+MI_MAX_IMGDIMS+. To set the size of a dimension, 719set the property \verb+MI_ICV_DIM_SIZE+ (analogous to 720\verb+MI_ICV_ADIM_SIZE+). To specify the dimension to be set, add 721the dimension to the property (adding zero corresponds to the fastest 722varying dimension --- add zero for the ``A'' dimension, one for the 723``B'' dimension, etc.). Voxel separation and 724location can be inquired about through the properties 725\verb+MI_ICV_DIM_STEP+ and \verb+MI_ICV_DIM_START+ (analogous to 726\verb+MI_ICV_ADIM_STEP+ and \verb+MI_ICV_ADIM_START+), again 727adding the dimension number to the property. 728 729\subsubsection{Example: Reading with dimension conversion} 730 731Reading a $256 \times 256$ image with the first pixel at the patient's 732inferior, posterior, left side as short values between 0 and 32000: 733\begin{verbatim} 734 /* Create the icv */ 735 icv=miicv_create(); 736 (void) miicv_setint(icv, MI_ICV_TYPE, NC_SHORT); 737 (void) miicv_setstr(icv, MI_ICV_SIGN, MI_UNSIGNED); 738 (void) miicv_setint(icv, MI_ICV_VALID_MAX, 32000); 739 (void) miicv_setint(icv, MI_ICV_VALID_MIN, 0); 740 (void) miicv_setint(icv, MI_ICV_DO_DIM_CONV, TRUE); 741 (void) miicv_setint(icv, MI_ICV_ADIM_SIZE, 256); 742 (void) miicv_setint(icv, MI_ICV_BDIM_SIZE, 256); 743 (void) miicv_setint(icv, MI_ICV_KEEP_ASPECT, TRUE); 744 (void) miicv_setint(icv, MI_ICV_XDIM_DIR, MI_POSITIVE); 745 (void) miicv_setint(icv, MI_ICV_YDIM_DIR, MI_POSITIVE); 746 (void) miicv_setint(icv, MI_ICV_ZDIM_DIR, MI_POSITIVE); 747 748 /* Open the file, attach the image variable */ 749 cdfid=ncopen(filename, NC_NOWRITE); 750 751 /* Attach image variable */ 752 img=ncvarid(cdfid, MIimage); 753 (void) miicv_attach(icv, cdfid, img); 754 755 /* Get the data - we assume that coord and count are set properly */ 756 (void) miicv_get(icv, coord, count, image); 757 758 /* Close the file and free the icv */ 759 (void) ncclose(cdfid); 760 (void) miicv_free(icv); 761\end{verbatim} 762 763 764\end{document} 765 766