Skip to content

Concepts

Tobias edited this page Feb 1, 2019 · 3 revisions

DCMJS Concepts

General overview about important classes and how they are connected.

DICOM data container

To capsulate DICOM datasets there is a class called DICOMZero. One important member property is datasets which represents an array of DICOM instances. Storing the result of a request in such a container object is useful to propagate the information to a viewer object.

The DICOMZero class also offers methods to handle the reading of local DICOM files or extracting zipped DICOM files.

Retrieve DICOM data from a PACS

The class DICOMWEB offers methods to retrieve information on different levels. Since you get meta data information with patients(), studies(), series(), instances() by automatically doing a QIDO-RS request, you actually retrieving pixel data only with calling instance() which leads to a WADO-RS request.

Initialization

function downloadProgress(progressEvent) {
    status(`Downloaded ${(progressEvent.loaded / 1024 / 1024).toFixed(2)} MB so far... `);
}

const rootURL = 'http://<HOST>:<PORT>/dcm4chee-arc/aets/DCM4CHEE';
const dicomweb = new dcmjs.DICOMWEB({
    progressCallback: downloadProgress,
    rootURL: rootURL,
});

The rootURL parameter is mandatory.

Requests

The result of every of the mentioned DICOMWEB class methods is a Promise object, which avoids blocking the main thread. In order to deal with the results you have to wait until the Promise is resolved.

dicomweb.instance(studyInstanceUID, seriesInstanceUID, sopInstanceUID).then(arrayBuffer => {
  // do something with the arrayBuffer...
});

Here is an actual example how to chain the methods instances() and instance() which first get the meta data of all instances within a given DICOM series and then use the instance UID to retrieve the data for every instance.

function loadDicomSeries(studyInstanceUID, seriesInstanceUID, seriesContainer){
    let promise = new Promise(function (resolve, reject) {
        dicomweb.instances(studyInstanceUID, seriesInstanceUID).then(instancesResponses => {
            console.log("download series " + seriesInstanceUID)
            instancesResponses.forEach(instancesResponse => {
                let response = DCMJS.data.DicomMetaDictionary.namifyDataset(instancesResponse);
                let sopInstanceUID = response.SOPInstanceUID.Value[0]; dicomweb.instance(studyInstanceUID, seriesInstanceUID, sopInstanceUID).then(arrayBuffer => {
                    let dataset = seriesContainer.datasetFromArrayBuffer(arrayBuffer);
                    seriesContainer.datasets.push(dataset);
                    if (seriesContainer.datasets.length == instancesResponses.length) {
                        console.log("download finished")
                        resolve()
                    }
                });
            });
        });
    });
    return promise;
}

The result of this method loadDicomSeries also returns a Promise which can be used in an application to wait until the data is loaded an then visualize it. Besides the series information, the method expects an object of the container class DICOMZero where the data is downloaded and preserved to transfer it to a viewer.

Viewer class

The Viewer class is responsible to take the mentioned datasets property of a DICOMZero object to be prepared for display it.

Example to create a Viewer:

var viewerOptions = {
  'width': 350,
  'height': 350,
}

viewerLeft = new Viewer(dicomZero.datasets, viewerOptions);
viewerLeft.display('#viewer');

This example expects the dicomZero to be an instance of DICOMZero containing datasets. Also on the HTML DOM tree there has to be an element with an ID named viewer.

Example on the HTML side:

<div id="viewer" style="width:350px; height:350px; background-color:black"></div>

Displaying DICOM data

Since the display method of Viewer is called, the custom cornerstone image loader are registered. These loaders are using a id schema by which cornerstone decides which loader is used to load the actual image data correctly.

But first, the Viewer must be informed that there is a dicom dataset which is referenced by a cornerstone image id. To create those image ids there are some add-* methods.

The data stored within Viewer.datasets is added to the so called Viewer.baseStack by just calling Viewer.display() which uses one of the add methods according to the type of image:

At the moment these loaders are implemented:

  • dcmjsImageLoader: standard single frame DICOM image loader
  • dcmjsSEGImageLoader: multiframe DICOM SEG image loader
  • dcmjsMultiframeImageLoader: multiframe DICOM image loader
  • dcmjsPMImageLoader: multiframe DICOM PM image loader (for example an ADC map)
  • dcmjsPMOverlayLoader: multiframe DICOM PM image overlay loader (for example a local difference measure map)

Adding DICOM data as Overlay

To add DICOM overlay on a second layer use the methods.

  • addSegmentation(dataset)
  • addParametricMapOverlay(dataset)

The methods are creating a new Cornerstone stack which is added to the tool state.