2

I'm trying to display multi-frame dicom images in a browser using HTML5 canvas and javascript. So far I can render single framed images just fine but I'm having trouble with multi framed images.

For parsing the file I'm using the DicomParser plugin.

When I break the data into it's fragments(frames) and try to display them the canvas just renders bars of noise. Heres an example of rendering a single frame from a multi frame image.

Noise produced by loading single frame from multiframe dicom image

Below is the javscript code

// CREATE A CANVAS REFERENCE
// -------------------------------------------------------------------------------------------------
var canvas = document.getElementById( 'canvas' );
canvas.with = 200;
canvas.height = 200;


// ADD A HANDLER FOR READING FILES FROM COMPUTER
// -------------------------------------------------------------------------------------------------
var dicomFile = document.getElementById( 'dicomfile' );

dicomFile.onchange = function( evt ) {
    var tgt = evt.target || window.event.srcElement,
        files = tgt.files;


// FILEREADER SUPPORT
// ---------------------------------------------------------------------------------------------
if ( FileReader && files && files.length ) {
    var fr = new FileReader(),
        extension = files[ 0 ].name.split( '.' ).pop().toLowerCase();

    // IF EXTENSION IS NOT DCM ,THEN STOP PROCESSING FURTHER AND EXIT.
    if ( extension !== 'dcm' ) {
        alert( 'please choose a Dicom file' );
        return;
    } else {

        // PARSE AND PROCESS THE DICOM FILE.
        fr.onload = function( e ) {

            var dicomArray = new Uint8Array( e.target.result ), 

                // PARSE THE DICOM FILE
                dataSet = dicomParser.parseDicom( dicomArray ),

                // GET WIDTH AND HEIGHT OF THE DICOM IMAGE.
                width = dataSet.uint16( 'x00280011' ), height = dataSet.uint16( 'x00280010' ),

                // GET THE PIXEL DATA ELEMENT FROM THE DATASET.
                pixelDataElement = dataSet.elements.x7fe00010;

            // NOW GET THE PIXEL DATA FROM THE DICOM FILE.
            var pixelData = [];

            pixelDataElement.basicOffsetTable.forEach( function(offset){ 
                pixelDataElement.fragments.forEach(function(fragment){
                    pixelData.push( new Uint8Array( dataSet.byteArray.buffer, offset, fragment.length ) );
                });
            });

            // NOW WE HAVE GOT WIDTH, HEIGHT AND PIXEL DATA WHICH IS ALL IT TAKES TO RENDER A IMAGE TO THE CANVAS.
            canvas.width = width;
            canvas.height = height;

            // GET CONTEXT
            var context = canvas.getContext( '2d' ),

            // GET IMAGE DATA TO UPDATE
                imageData = context.getImageData( 0, 0, width, height ),
                data = imageData.data;

            // UPDATING ALPHA
            for ( var i = 3, k = 0; i < data.byteLength; i = i + 4, k = k + 2 ) {

                // CONVERT 16-BIT TO 8-BIT ,BECAUSE WE CANNOT RENDER A 16-BIT VALUE TO THE CANVAS.
                var result = ((pixelData[0][ k + 1 ] & 0xFF) << 8) | (pixelData[0][ k ] & 0xFF);
                result = (result & 0xFFFF) >> 8;
                data[ i ] = 255 - result;
            }

            imageData[0] =  data[0];

            context.putImageData( imageData, 0, 0 );

            // SHOW THE CANVAS
            canvas.style.display = 'block';
        };
        fr.readAsArrayBuffer( this.files[ 0 ] );
    }
}
};

Could anyone tell me where I'm going wrong. Any information at all, however general, would be helpful.

The end goal is to use these frames as textures for webGl and three.js to create volumetric rendering of dicom images

2 Answers 2

3

The image frames in your multi-frame file are likely compressed and dicomParser does not include decompression code. Take a look at CornerstoneWADOImageLoader for codecs and how to use them: https://github.com/chafey/cornerstoneWADOImageLoader

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for recommending this image loader, so far it looks much more robust than dicomParser. Still early days yet but I'm hopeful this will work with webGL/three.js
Yup, its looking pretty good. Was able to create an image stack with relatively little trouble. You were right too about the image being compressed.
1

Another solution is to use dicom.ts

display a DICOM on a canvas with a few lines of code:

  // parse the raw data
  const image = dicomts.parseImage(new DataView(rawBuffer));
  // render to canvas element
  const renderer = new dicomjs.Renderer(canvas);
  // decode, and display frame 0 on the canvas
  renderer.render(image, 0);

please find working codepen here: https://codepen.io/nickhingston/pen/PojrXZg

(Disclaimer - somewhat an advert for our lib, but probably the simplest solution i've seen)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.