1.2.3. Loading from a file

This is the simplest method for loading volume data, assuming that the volume is stored on disk and there exists an SoVolumeReader( C++ | Java | .NET ) class for the file format. This is true of course for the formats for which VolumeViz has a built-in reader, however applications can create their own volume reader classes (described later). VolumeViz will try to automatically select a volume reader class based on the file extension. For example VolumeViz will automatically use the SoVRLdmFileReader( C++ | Java | .NET ) class for files with the extension ".ldm" (the LDM file format defined by FEI). VolumeViz supports a number of common formats including DICOM and SEGY (discussed in more detail later). In addition to single data files, some VolumeViz readers support loading a volume stored as a stack of separate image files. We have already seen a simple example of setting SoVolumeData( C++ | Java | .NET )’s filename field in the Section 1.1.4, “Quick Start”.

[Important]

Note that the application can also query the volume reader using the getReader() method. If called after the filename field has been set, this method will return a pointer to the instance of the SoVolumeReader( C++ | Java | .NET ) sub-class that VolumeViz selected to load this file (or the reader specified using the setReader() method). This can be useful in order to call data format specific methods provided by that volume reader class, for example to get custom XML tags from an LDM file header.

In this section we will discuss:

The following table shows the built-in VolumeViz file readers and the file name extension(s) associated with each reader class. The filename extension is not case sensitive

File extension Reader class Description
.am SoVRAmFileReader( C++ | Java | .NET ) Avizo Mesh file format
.dc3, .dic, .dicom SoVRDicomFileReader( C++ | Java | .NET ) DICOM file format
.fld SoVRAvsFileReader( C++ | Java | .NET ) AVS field file format
.ldm SoVRLdmFileReader( C++ | Java | .NET ) Large Data Management file format
.sgy or .segy SoVRSegyFileReader( C++ | Java | .NET ) SEG Y revision 1 file format
.vol SoVRVolFileReader( C++ | Java | .NET ) Vol file format
.vox SoVRVoxFileReader( C++ | Java | .NET ) Vox file format
.lst SoVRRasterStackReader( C++ | Java | .NET ) Lst file format
.tiff, .tif SoVRTiffFileReader( C++ | Java | .NET ) Tiff file format
.mrc SoVRMrcFileReader( C++ | Java | .NET ) Mrc file format

If the filename does not have an extension or does not have the appropriate extension, the application can still use a specific volume reader to load the file, but must set the volume reader explicitly using the SoVolumeData( C++ | Java | .NET ) node’s setReader() method. For example, if we know the volume file contains data in the VOL format, but the filename does not have the appropriate extension, the following code will force VolumeViz to read the data as VOL format.


C++
// Load volume in VOL format
SoVRVolFileReader* pReader = new SoVRVolFileReader;
pReader->setFilename( "myVolData.xxx" );

SoVolumeData* pVolData = new SoVolumeData();
pVolData->setReader( *pReader );

.NET
// Load volume in VOL format
SoVRVolFileReader reader = new SoVRVolFileReader();
reader.SetFilename( "myVolData.xxx" );

SoVolumeData VolData = new SoVolumeData();
VolData.Reader = reader;

Java
// Load volume in VOL format
SoVRVolFileReader reader = new SoVRVolFileReader();
reader.setFilename( " myVolData.xxx " );

SoVolumeData volData = new SoVolumeData();
volData.setReader( reader, false );
[Important]

The C++ and Java versions of setReader() have a second parameter called takeOwnership. When this parameter is false (the default), the volume reader object is owned by the application and must be managed by the application. When this parameter is true, VolumeViz manages the reader object.

If the file is not in a format directly supported by VolumeViz, but contains volume data in a contiguous block of values organized row-by-row, you can use the generic reader SoVRGenericFileReader( C++ | Java | .NET ). This is useful to load so-called “raw” data files. You will need to specify the volume characteristics extent, data type and dimensions. This information may be in a separate text file associated with the data file or it may be specified in a “header” at the beginning of the data file. The application can optionally specify the size of the file header (if any), in other words the number of bytes to skip over before starting to load values. For example we know that a VOL format file normally contains a 40 byte header followed by the data values. So knowing that the Syn_64 example data set is 64x64x64 with unsigned byte data values, the following code will load that data using the generic reader.


C++
SbBox3f extent(-1, -1, -1, 1, 1, 1 );
SbVec3i32 dimensions(64,64,64);
SoDataSet::DataType dataType = SoDataSet::UNSIGNED_BYTE;
int headerSize = 40;

SoVRGenericFileReader* pReader = new SoVRGenericFileReader;
pReader->setFilename( “$OIVHOME/src/VolumeViz/Data/Syn_64.vol” );
pReader->setDataChar( extent, dataType, dimensions, headerSize );

SoVolumeData* pVolData = new SoVolumeData();
pVolData->setReader( *pReader );

.NET
SbBox3f extent = new SbBox3f(-1, -1, -1, 1, 1, 1 );
SbVec3i32 dimensions = new SbVec3i32(64,64,64);
SoDataSet.DataTypes dataType = SoDataSet.DataTypes.UNSIGNED_BYTE;
int headerSize = 40;

SoVRGenericFileReader Reader = new SoVRGenericFileReader();
Reader.SetFilename( “$OIVHOME/src/VolumeViz/Data/Syn_64.vol” );
Reader.SetDataChar( extent, out dataType, dimensions, headerSize );

SoVolumeData VolData = new SoVolumeData();
VolData.Reader = Reader;

Java
SbBox3f extent = new SbBox3f( -1, -1, -1, 1, 1, 1 );
SbVec3i32 dimensions = new SbVec3i32(64,64,64);
SoDataSet.DataTypes dataType = SoDataSet.DataTypes.UNSIGNED_BYTE;
int headerSize = 40;

SoVRGenericFileReader reader = new SoVRGenericFileReader();
reader.setFilename( "$OIVHOME/src/VolumeViz/Data/Syn_64.vol" );
reader.setDataChar( extent, dataType, dimensions, headerSize );

SoVolumeData volData = new SoVolumeData();
volData.setReader( reader );

If the volume is stored as multiple image files, one slice per image, you can use the SoVRRasterStackReader( C++ | Java | .NET ) class. This is useful to load a so-called “stack of images”. The individual image files may be in any image format supported by Open Inventor, for example JPEG, PNG or TIFF. See the FileType enumeration in the SoTexture node for a complete list of supported image file formats. The images can even be in different formats, but all the images must be the same size. The X and Y dimensions of the volume are determined by the image size. The Z dimension is determined by the number of slices.

[Important]

DICOM data may also be delivered as multiple images, but there is a separate reader class specifically for this data format which we will discuss in a later section.

In order to load a stack of images there must exist a file containing a list of the image file names. If necessary the application can create this file “on the fly”. The image file names may be simple file names or complete file paths. If an image file name is a simple file name VolumeViz will try to open it in the directory that contains the list file. The order of the file names in the list file determines how the slices are loaded. VolumeViz assumes the first image is slice zero, at the “back” of the volume, and subsequent slices are loaded in order of increasing Z value.

The list file may also contain an optional header that specifies characteristics of the volume that cannot be inferred from the image files. See the SoVRRasterStackReader( C++ | Java | .NET ) for a complete list of parameters that can be specified. This is useful to specify the volume extent in 3D or for color images to specify that the data values should be taken from a specific channel, for example the Red values in the image.

For the classic TeddyBear example data (not included with VolumeViz but available on the web), the list file might look like this, where the “Size” parameter really means “extent” in this context:

Parameters {
  Size 10.000000 10.000000 10.000000 1250.000000 1250.000000 500.000000
}
teddybear000.jpg
teddybear001.jpg
teddybear002.jpg
teddybear003.jpg
teddybear004.jpg
...

Once we have a list file, loading the data is essentially the same as the previous simple example of setting a specific volume reader:


C++
SoVRRasterStackReader* pReader = new SoVRRasterStackReader;
pReader->setFilename( "/MyData/teddybear/teddybear.lst" );
SoVolumeData* pVolData = new SoVolumeData;
pVolData->setReader( *pReader );

.NET
SoVRRasterStackReader Reader = new SoVRRasterStackReader();
Reader.SetFilename( "/MyData/teddybear/teddybear.lst" );
SoVolumeData VolData = new SoVolumeData();
VolData.Reader = Reader;

Java
SoVRRasterStackReader reader = new SoVRRasterStackReader();
reader.setFilename( "/MyData/teddybear/teddybear.lst" );
SoVolumeData volData = new SoVolumeData();
volData.setReader(reader);

Voxels in an RGBA volume are UNSIGNED_INT32 values, containing 8 bits each of Red, Green, Blue and Alpha. All rendering nodes (slices, volume rendering, etc) work with RGBA volumes. Region of Interest, clipping and other features also work with RGBA volumes. However because the volume already specifies the colors to be used for rendering, the data range and transfer function are ignored. Lighting works with RGBA volumes using gradient vectors computed from the luminance value of the voxels.