1.2.7. DICOM Data

DICOM is a widely used format for storing medical image data (CT, MRI, etc), defined by the National Electrical Manufacturers Association (NEMA) (http://medical.nema.org). The SoVRDicomFileReader SoVRDicomFileReader SoVRDicomFileReader class can load a volume from a single DICOM file or from a list of DICOM files (stack of images). Loading a volume from a single DICOM file is the same as loading any other format supported by VolumeViz. Loading a volume from a list of DICOM files can be done using a list file or by specifying a list of filenames. Using a list file is the same as loading a stack of images using the SoVRRasterStackReader SoVRRasterStackReader SoVRRasterStackReader except the list file should not contain any header. Each line in the list file may be a full path containing directory names or a simple file name. Simple file names are assumed to be in the same directory as the list file. The application can also specify a list of file paths using the setFilenameList() method. This is useful, for example, if the application user is allowed to select a list of files in a file selection dialog.

Unlike a raster stack, the position of each slice in the volume is determined by the location value in its file header and not by the order of the file name in the list. Also unlike a raster stack consisting of (for example) JPEG or PNG images, a DICOM file in the list may contain more than one slice of the volume. The reader handles this automatically. The first file in the list is considered the “reference” for the volume and all slices must be compatible with this one. Specifically this means that subsequent files must have the same width, height, data type and so on. The volume is oriented in 3D space in a natural way for medical images. The slice width is along the X axis, the slice height is along the Y axis and slice location values increase along the Z axis.

Note when using a list file: If the file extension is not “.dc3”, “.dic” or “.dicom” VolumeViz will not automatically select the DICOM volume reader. You can either give the list file one of the DICOM file extensions or force VolumeViz to use the DICOM reader by creating an instance of SoVRDicomFileReader SoVRDicomFileReader SoVRDicomFileReader and calling the setReader() method as described in the “Non-standard extension” sub-section of Section 1.2.3, “Loading from a file”.

The volume reader will automatically get the correct volume dimensions, data type, extent (voxel size/spacing) and number of significant bits from the DICOM file header. The reader will also apply the data adjustment (if any) specified by the RescaleSlope and RescaleIntercept tags in the DICOM file header, i.e.: actualValue = slope * storedValue + intercept. As part of this process the reader will automatically convert unsigned data to the corresponding signed data type if necessary (in other words if the rescale calculation produces negative values). The application can also explicitly specify the volume data type. This allows, for example, converting float data values to more compact integer values.

[Important]

The DICOM reader only uses the rescale slope and intercept values from the first file in the list. It does not currently handle the (less common) case where each file contains different rescale values.

The SoVRDicomData SoVRDicomData SoVRDicomData class allows the application to access DICOM specific data in the file header(s). One way to do this is to query the volume reader from the SoVolumeData SoVolumeData SoVolumeData then query the SoVRDicomData SoVRDicomData SoVRDicomData object from the reader. However the application can also create an instance of SoVRDicomData SoVRDicomData SoVRDicomData explicitly and then open DICOM files directly using the readDicomHeader() method. SoVRDicomData SoVRDicomData SoVRDicomData provides methods such as getSliceSpacing() to query some of the commonly used values. However it also provides the getDicomInfo() method which allows the application to query any DICOM tag (if present in the file) by its hexadecimal group and tag number.

SoVRDicomFileReader* pReader = (SoVRDicomFileReader*)pVolData->getReader();
const SoVRDicomData &dicomData = pReader->getDicomData();
float rescaleSlope = dicomData.getDefaultSlope();
SbString str = dicomData.getDicomInfo( 0x28, 0x1053 );
if (! str.isEmpty())
{
  rescaleSlope = str.toFloat();
}
SoVRDicomFileReader Reader = (SoVRDicomFileReader)VolData.GetReader();
SoVRDicomData dicomData = Reader.GetDicomData();
float rescaleSlope = dicomData.GetSlope();
string str = dicomData.GetDicomInfo(0x28, 0x1053);
if (str.Length > 0)
{
  rescaleSlope = float.Parse(str);
}
SoVRDicomFileReader reader = (SoVRDicomFileReader)volData.getReader();
SoVRDicomData dicomData = reader.getDicomData();
float rescaleSlope = dicomData.getSlope();
String str = dicomData.getDicomInfo((short)0x28, (short)0x1053);
if (str.length() > 0)
{
  rescaleSlope = Float.valueOf(str);
}