Loading DICOM Files

<< Click to Display Table of Contents >>

Navigation:  XStream® HDVR® SDK > Implementation Concepts > Data Loading Fundamentals >

Loading DICOM Files

Previous pageReturn to chapter overviewNext page

C++ C++ Java Java .NET .NET

Summary

 

The XStream® HDVR® SDK provides a number of utility classes and methods to facilitate the loading of DICOM files. Some of these utilities load DICOM files directly, and others scan directories for DICOM files with specific tags or properties. These classes and methods can be used to analyze a set or hierarchy of directories to build a database of DICOM series, and then load specific DICOM series into a XStream HDVR application for rendering. Both synchronous and asynchronous methods are available in this class.

 

The XStream HDVR SDK allows the use of a user-defined custom data loading function in lieu of the built-in DICOM loading methods. The Custom Loading Function section discusses the use of this feature.

 

Loading a Single DICOM Series

 

The most straightforward DICOM loading method is the IServerContext::LoadDicomDirectory() method. This method will load a single DICOM series contained in a single directory. The directory should contain only a single DICOM series: no other files (such as index files or files from other series) should be present in the directory, or loading errors may result. The IServerContext::LoadDicomDirectory() method takes as an output parameter the address of a pointer to an IVolumeDataContext object, and takes as an input parameter the path to the dataset. The IServerContext::LoadDicomDirectory() method will load the series, allocate the IVolumeDataContext object, and fill it with the volume data.

 

When using the IServerContext::LoadDicomDirectory() method, the target directory should contain only a single DICOM series: no other files (such as index files or files from other series) should be present in the directory, or loading errors may result.

 

IVolumeDataContext *pVolumeData = NULL;

pServerContext->LoadDicomDirectory(&pVolumeData, "/data/DICOM/dataset1");

 

The most straightforward DICOM loading method is the hdrcServerContext.loadDicomDirectory() method. This method will load a single DICOM series contained in a single directory. The directory should contain only a single DICOM series: no other files (such as index files or files from other series) should be present in the directory or loading errors may result. The hdrcServerContext.loadDicomDirectory() method takes the path to the dataset as an input parameter and will return a reference to a hdrcVolumeDataContext containing the volume data.

 

When using the hdrcServerContext.loadDicomDirectory() method, the target directory should contain only a single DICOM series: no other files (such as index files or files from other series) should be present in the directory, or loading errors may result.

 

hdrcVolumeDataContext volumeData = NULL;

volumeData = serverContext.loadDicomDirectory("/data/DICOM/dataset1");

 

The ILiteDICOMFileContext Object

 

Several of the C++ methods in this section make use of ILiteDICOMFileContext objects. The ILiteDICOMFileContext class stores the header data associated with an individual DICOM file. The IServerContext::LoadDICOMFromFileList() and IServerContext::ScanDICOMDirectory() methods are used to build an array of ILiteDICOMFileContext objects that represent either a single DICOM series, or a collection of series in a list or hierarchy of directories. The IServerContext::LoadDICOMFromFileList() method is then used to load the actual DICOM dataset associated with some or all of the ILiteDICOMFileContext objects generated from the IServerContext::LoadDICOMFromFileList() or IServerContext::ScanDICOMDirectory() methods.

 

A search for DICOM file tags may be performed using the ILiteDICOMFileContext::GetTags() method. This method will search the ILiteDICOMFileContext objects generated from the IServerContext::LoadDICOMFromFileList() or IServerContext::ScanDICOMDirectory() methods. This method takes as input parameters the array of ILiteDICOMFileContext objects generated from a directory search, the number of ILiteDICOMFileContext objects in the array, an array of DICOM_TAG_REQUEST structures that designate a set of DICOM tags to search for, and the number of DICOM_TAG_REQUEST structures in the array. The final parameter is the address of a DICOM_TAG_DATA array that will receive the DICOM tags found in the search.

 

The DICOM_TAG_REQUEST structure has three members. The DICOM_TAG_REQUEST::m_dataType member is a value from the ENUM_DICOM_TAG_DATA_TYPES enumeration that designates the type of data in the requested tag (integer, float, string, etc.). The DICOM_TAG_REQUEST::m_index member stores the index of the data to be retrieved from the tag. Most DICOM tags have only a single value, so this will generally be 0, but some tags have more than one data value associated with them. The DICOM_TAG_REQUEST::m_tag member is a DICOM_TAG structure that is set with the element and group number (in hexadecimal) associated with the searched-for tag.

 

The result of the search will be stored in a two dimensional array of DICOM_TAG_DATA objects. The size of each array depends on the number of ILiteDICOMFileContext objects to be searched and the number of DICOM_TAG_REQUEST objects to be searched for. Each DICOM_TAG_DATA object consists of the different data types that may comprise a DICOM tag. The appropriate DICOM_TAG_DATA member field is determined by the data type in the corresponding DICOM_TAG_REQUEST::m_dataType member. See Loading DICOM Data from a Header List for an example of how to use the ILiteDICOMFileContext::GetTags() method.

 

Several of the Java/.NET methods in this section make use of hdrcILiteDICOMFileContext objects. The hdrcILiteDICOMFileContext class stores the header data associated with an individual DICOM file. The hdrcServerContext.loadDICOMFromFileList() and hdrcServerContext.scanDICOMDirectory() methods are used to build an array of hdrcLiteDICOMFileContext objects that represent either a single DICOM series, or a collection of series in a list or hierarchy of directories. The hdrcServerContext.loadDICOMFromFileList() method is then used to load the actual DICOM dataset associated with some or all of the hdrcILiteDICOMFileContext objects generated from the hdrcServerContext.loadDICOMFromFileList() or hdrcServerContext.scanDICOMDirectory() methods.

 

A search for DICOM file tags may be performed using the hdrcILiteDICOMFileContext.GetTags() method. This method will search the hdrcILiteDICOMFileContext objects generated from the hdrcServerContext::loadDICOMFromFileList() or hdrcServerContext::scanDICOMDirectory() methods. This method takes as input parameters the array of hdrcILiteDICOMFileContext objects generated from a directory search, the number of hdrcILiteDICOMFileContext objects in the array, an array of DICOM_TAG_REQUEST structures that designate a set of DICOM tags to search for, and the number of DICOM_TAG_REQUEST structures in the array. The final parameter is the address of a DICOM_TAG_DATA array that will receive the DICOM tags found in the search.

 

The DICOM_TAG_REQUEST structure has three members. The DICOM_TAG_REQUEST.m_dataType member is a DCTD identifier stored as a static member DICOM_TAG_DATA class that designate the type of data in the requested tag (integer, float, string, etc.). The DICOM_TAG_REQUEST.m_index member stores the index of the data to be retrieved from the tag. Most DICOM tags have only a single value, so this will generally be 0, but some tags have more than one data value associated with them. The DICOM_TAG_REQUEST.m_tag member is a DICOM_TAG structure that is set with the element and group number (in hexadecimal) associated with the searched-for tag.

 

The result of the search will be stored in a two dimensional array of DICOM_TAG_DATA objects. The size of each dimension depends on the number of hdrcILiteDICOMFileContext objects to be searched and the number of DICOM_TAG_REQUEST objects to be searched for. Each DICOM_TAG_DATA object consists of the different data types that may comprise a DICOM tag. The appropriate DICOM_TAG_DATA member field is determined by the data type in the corresponding DICOM_TAG_REQUEST.m_dataType member. See Loading DICOM Data from a Header List for an example of how to use the hdrcILiteDICOMFileContext.getTags() method.

 

Loading DICOM Headers from a List of Directories

 

The IServerContext::LoadDICOMFromFileList() method is used to create an array of ILiteDICOMFileContext objects with information describing the properties of DICOM files that are stored in a list of directories. The IServerContext::LoadDICOMFromFileList() method takes as input parameters an array of character strings representing the directories containing DICOM files to be analyzed, the number of directories stored in the array, and a pointer to the IAllocator object used to allocate the ILiteDICOMFileContext array. The IServerContext::LoadDICOMFromFileList() method takes as an output parameter a pointer to an array that will be filled with ILiteDICOMFileContext object pointers. The output array will have one object pointer per file. The array of ILiteDICOMFileContext objects can then be processed to determine which DICOM files should be loaded. The loading of DICOM files represented by ILiteDICOMFileContext objects is handled by the IServerContext::LoadSeriesFromDICOMList() method, described below.

 

// Specify directories to scan for DICOM files.

char *dicomPaths[] = { 

   "/data/DICOM/dataset1",

   "/data/DICOM/dataset2"

};

 

// Get array allocator.

IAllocator *pAllocator;

pLibrary->GetAllocator(HCAP_GENERAL, &pAllocator);

 

// Load DICOM headers.

ILiteDICOMFileContext **pDicomFileHeaders;

pServerContext->LoadDICOMFromFileList(&pDicomFileHeaders, dicomPaths, 2, pAllocator);

 

The hdrcServerContext.loadDICOMFromFileList() method is used to create an array of hdrcILiteDICOMFile objects with information describing the properties of DICOM files that are stored in a list of directories. The hdrcServerContext.LoadDICOMFromFileList() method takes as an input parameter an array of character strings representing the directories containing DICOM files to be analyzed. The hdrcServerContext.LoadDICOMFromFileList() method returns an array that will be filled with hdrcILiteDICOMFile object references. The output array will have one object reference per file. The array of hdrcLiteDICOMFile objects can then be processed to determine which DICOM files should be loaded. The loading of DICOM files represented by hdrcILiteDICOMFile objects is handled by the hdrcServerContext.loadSeriesFromDICOMList() method, described below.

 

// Specify directories to scan for DICOM files.

String[] dicomPaths = new String[] { 

   "/data/DICOM/dataset1",

   "/data/DICOM/dataset2"

};

 

// Load DICOM headers.

hdrcILiteDICOMFile dicomFileHeaders;

dicomFileHeaders = serverContext.loadDICOMFromFileList(dicomPaths);

 

 

Loading DICOM Headers from a Recursive Directory Search

 

The IServerContext::ScanDICOMDirectory() method is used to recursively scan a directory structure, and to create an array of ILiteDICOMFileContext objects that contain information describing the properties of the identified DICOM files. The IServerContext::ScanDICOMDirectory() method takes as input parameters the path to the root directory to initiate the search, and a pointer to the IAllocator object used to allocate the ILiteDICOMFileContext array. The method takes as output parameters the address of an array of character strings representing the paths to the DICOM files that have been processed by the function, a pointer to an integer containing the number of processed files, and a pointer to an array that will be filled with ILiteDICOMFileContext object pointers. The output array will have one object pointer per file. The array of ILiteDICOMFileContext objects can then be processed to determine which DICOM files should be loaded. The loading of DICOM files represented by ILiteDICOMFileContext objects is handled by the IServerContext::LoadSeriesFromDICOMList() method described below.

 

ILiteDICOMFileContext **pDicomFileHeaders;

char **pathList;

h_uint32 numFiles;

 

IAllocator *pAllocator;

pLibrary->GetAllocator(HCAP_GENERAL, &pAllocator);

 

pServerContext->ScanDICOMDirectory(&pDicomFileHeaders, &pathList, &numFiles, "/data/DICOM/", pAllocator);

 

The hdrcServerContext.scanDICOMDirectory() method is used to recursively scan a directory structure, and create to an array of hdrcILiteDICOMFileContext objects that contain information describing the properties of the identified DICOM files. The hdrcServerContext.scanDICOMDirectory() method takes as an input parameter the path to the root directory to initiate the search. The hdrcServerContext.scanDICOMDirectory() method returns an array that will be filled with hdrcILiteDICOMFileContext object references. The output array will have one object reference per file. The array of hdrcLiteDICOMFileContext objects can then be processed to determine which DICOM files should be loaded. The loading of DICOM files represented by hdrcILiteDICOMFileContext objects is handled by the hdrcServerContext.loadSeriesFromDICOMList() method, described below.

 

hdrcILiteDICOMFile[] dicomHeaders = serverContext.scanDICOMDirectory("/data/DICOM/");

 

Loading DICOM Data from a Header List

 

The IServerContext::LoadSeriesFromDICOMList() method is used to load a DICOM dataset from an array of ILiteDICOMFileContext objects created from either the IServerContext::LoadDICOMFromFileList() or IServerContext::ScanDICOMDirectory() methods. The IServerContext::LoadSeriesFromDICOMList() method takes as input parameters a pointer to an array of ILiteDICOMFileContext object pointers, a series UID for the files to be loaded, the number of ILiteDICOMFileContext objects in the input array, and the address of an IVolumeDataContext pointer that will receive the volume data from the input dataset. Only files with the specified series UID will be loaded for inclusion in the dataset. Note that this method releases the ILiteDICOMFileContext objects from memory on the server. You may no longer use any of the objects passed in after calling this method.

 

pServerContext->ScanDICOMDirectory(&pDicomFileHeaders, &pathList, &numFiles, "/data/DICOM/", pAllocator);

 

// Configure a DICOM_TAG_REQUEST to retrieve the series UID.

DICOM_TAG_REQUEST request;

request.m_dataType = DCTD_STRING;

request.m_index = 0;

request.m_tag.group = 0x0020;

request.m_tag.element = 0x000E;

 

// We are examining 1 ILiteDICOMFileContext file and have 1 DICOM_TAG_REQUEST. 

DICOM_TAG_DATA tagData[1][1];

 

// Retrieve the series UID from the ILiteDICOMFileContext array.

pDicomFileHeaders[0]->GetTags(pDicomFileHeaders, 1, &request, 1, &tagData);

 

// Load the DICOM series with the designated series UID into an IVolumeDataContext object for rendering.

IVolumeDataContext pVolumeData = NULL;

pServerContext->LoadSeriesFromDICOMList(&pVolumeData, 100, pDicomFileHeaders, tagData.string);

 

The hdrcServerContext.loadSeriesFromDICOMList() method is used to load a DICOM dataset from an array of hdrcILiteDICOMFile objects created from either the hdrcServerContext.loadDICOMFromFileList() or hdrcServerContext.scanDICOMDirectory() methods. The hdrcServerContext.loadSeriesFromDICOMList() method takes as input parameters an array of ILiteDICOMFile object references and a series UID for the files to be loaded. The hdrcServerContext.loadSeriesFromDICOMList() method will return a hdrcVolumeDataContext object that contains the volume data from the input dataset. Only files with the specified series UID will be loaded for inclusion in the dataset. Note that this method releases the hdrcILiteDICOMFile objects from memory on the server. You may no longer use any of the objects passed in after calling this method.

 

// Get an array of hdrcILiteDICOMFile objects from a directory scan.

hdrcILiteDICOMFile[] dicomHeaders = m_pServer.scanDICOMDirectory("/data/DICOM/");

int arraySize = dicomHeaders.Length;

 

// Create a tag request to retrieve the (0010, 0010) tag.

DICOM_TAG_REQUEST[] request = new DICOM_TAG_REQUEST[1];

DICOM_TAG tag = new DICOM_TAG(0x0010, 0x0010);

request[0] = new DICOM_TAG_REQUEST(tag, DICOM_TAG_DATA.DCTD_STRING, 0);

 

// Create a two dimensional array to store the returned tag data.

// This array must have dimensions of [dicomHeaders.Length][request.Length].

// In this way, for each header object in the array, an array of results is returned.

DICOM_TAG_DATA[][] arrResult = new DICOM_TAG_DATA[arraySize][];

for (int i = 0; i < arraySize; i++)

{

   arrResult[i] = new DICOM_TAG_DATA[1];

   arrResult[i][0] = new DICOM_TAG_DATA();  

}

 

// Get the tag data.

dicomHeaders[0].getTags(dicomHeaders, request, arrResult);

 

// Load the DICOM series with the designated series UID into a hdrcVolumeDataContext object for rendering.

hdrcVolumeDataContext volumeData = NULL;

volumeData = serverContext.loadSeriesFromDICOMList(dicomFileHeaders, tagData.string);

 

// Get an array of hdrcILiteDICOMFile objects from a directory scan.

hdrcILiteDICOMFile[] dicomHeaders = m_pServer.scanDICOMDirectory("/data/DICOM/");

int arraySize = dicomHeaders.Length;

 

// Create a tag request to retrieve the (0010, 0010) tag.

DICOM_TAG_REQUEST[] request = new DICOM_TAG_REQUEST[1];

DICOM_TAG tag = new DICOM_TAG(0x0010, 0x0010);

request[0] = new DICOM_TAG_REQUEST(tag, DICOM_TAG_DATA.DCTD_STRING, 0);

 

// Create a two dimensional array to store the returned tag data.

// This array must have dimensions of [dicomHeaders.Length][request.Length].

// In this way, for each header object in the array, an array of results is returned.

DICOM_TAG_DATA[][] arrResult = new DICOM_TAG_DATA[arraySize][];

for (int i = 0; i < arraySize; i++)

{

   arrResult[i] = new DICOM_TAG_DATA[1];

   arrResult[i][0] = new DICOM_TAG_DATA();  

}

 

// Get the tag data.

dicomHeaders[0].getTags(dicomHeaders, request, arrResult);

 

// Load the DICOM series with the designated series UID into a hdrcVolumeDataContext object for rendering.

hdrcVolumeDataContext volumeData = NULL;

volumeData = serverContext.loadSeriesFromDICOMList(dicomFileHeaders, tagData.string);

 

 

Asynchronous Dataset Loading

 

All of the C++ API methods discussed above in this section are synchronous methods. They will block until complete. Because loading a large number of DICOM headers or files can be time-consuming, it may not be optimal to use a synchronous blocking function for these operations. Corresponding asynchronous methods to the above synchronous methods can be used instead. These asynchronous methods have similar names to the synchronous method but begin with 'StartJob' and 'FinishJob'. The table below shows the appropriate asynchronous methods that match the corresponding synchronous counterpart.

 

IServerContext::LoadDicomDirectory()

IServerContext::StartJobLoadDicomDirectory()

IServerContext::FinishJobLoadDicomDirectory()

 

IServerContext::LoadDICOMFromFileList()

IServerContext::StartJobLoadDICOMFromFileList()

IServerContext::FinishJobLoadDICOMFromFileList()

 

IServerContext::ScanDICOMDirectory()

IServerContext::StartJobScanDICOMDirectory()

IServerContext::FinishJobScanDICOMDirectory()

 

IServerContext::LoadSeriesFromDICOMList()

IServerContext::StartJobLoadSeriesFromDICOMList()

IServerContext::FinishJobLoadSeriesFromDICOMList()

 

Each of the 'StartJob' asynchronous methods takes similar parameters to its synchronous counterpart, but also takes as an output parameter the address of an integer that designates a job ID value. This returned job ID value can be used with the IServerContext::GetJobInfo() method as an input parameter to track the progress and status of the asynchronous loading operation. The IServerContext::GetJobInfo() method returns as an output parameter a pointer to a JOBINFO  structure. The JOBINFO::jobprog value stores the job progress. This value will be 0 to 100, representing percentage of job completion, with a value of 100 indicating completion of the job.

 

All of the 'FinishJob' asynchronous methods take as an output parameter the address of either an IVolumeDataContext or ILiteDICOMFileContext, as appropriate to the individual method. This output parameter stores the result of the asynchronous operation upon completion. The 'FinishJob' methods also take as an input parameter the job ID value associated with the asynchronous operation. Each of the 'FinishJob' methods will block until the asynchronous operation completes.

 

h_int64 jobID;

 

// Start the asynchronous loading operation.

pServerContext->StartJobLoadDicomDirectory(&jobID, "/data/DICOM/dataset1");

 

JOBINFO jobInfo;

while(jobInfo.jobprog < 100 ) {

   // Get loading progress

   pServerContext->GetJobInfo(jobID, &jobInfo);

 

// Loading process is complete

IVolumeDataContext *pVolumeData = NULL;

pServerContext->FinishJobLoadDicomDirectory(&pVolumeData, jobID);

 

All of the Java/.NET API methods discussed above in this section are synchronous methods. They will block until complete. Because loading a large number of DICOM headers or files can be time-consuming, it may not be optimal to use a synchronous blocking function for these operations. Corresponding asynchronous methods to the above synchronous methods can be used instead. These asynchronous methods have similar names to the synchronous method but begin with 'startJob' and 'finishJob'. The table below shows the appropriate asynchronous methods that match the corresponding synchronous counterpart.

 

hdrcServerContext.loadDicomDirectory()

hdrcServerContext.startJobLoadDicomDirectory()

hdrcServerContext.finishJobLoadDicomDirectory()

 

hdrcServerContext.loadDICOMFromFileList()

hdrcServerContext.startJobLoadDICOMFromFileList()

hdrcServerContext.finishJobLoadDICOMFromFileList()

 

hdrcServerContext.scanDICOMDirectory()

hdrcServerContext.startJobScanDICOMDirectory()

hdrcServerContext.finishJobScanDICOMDirectory()

 

hdrcServerContext.loadSeriesFromDICOMList()

hdrcServerContext.startJobLoadSeriesFromDICOMList()

hdrcServerContext.finishJobLoadSeriesFromDICOMList()

 

Each of the 'startJob' asynchronous methods take similar parameters to their synchronous counterpart, but also also return an integer that designates a job ID value. This returned job ID value can be used with the hdrcServerContext.getJobInfo() method as an input parameter to track the process and status of the asynchronous loading operation. The hdrcServerContext.getJobInfo() method returns a reference to a hdrcJobInfo structure. The hdrcJobInfo.m_prog value stores the job progress. This value will be 0 to 100, representing percentage of job completion, with a value of 100 indicating completion of the job.

 

All of the 'finishJob' asynchronous methods will return either a hdrcVolumeDataContext or hdrcILiteDICOMFileContext, as appropriate to the individual method. This return value contains the result of the asynchronous operation upon completion. The 'finishJob' methods take as an input parameter the job ID value associated with the asynchronous operation. Each of the 'finishJob' methods will block until the asynchronous operation completes.

 

// Start the asynchronous loading operation.

long jobID = serverContext.startJobLoadDicomDirectory("/data/DICOM/dataset1);

 

hdrcJobInfo jobInfo;

while(jobInfo.m_prog < 100) {

   // Get loading progress

   jobInfo = serverContext.getJobInfo(jobID);

 

// Loading process is complete

hdrcVolumeDataContext volumeData;

volumeData = serverContext.finishJobLoadDicomDirectory(jobID);