Search code examples
javascriptwebglxtkmedical

Xtk : Can't display label map


I slightly changed demo #11 to load my images instead of the demo's.

I can load my MRI image just fine, see Demo. It also works if I load my label map as the main volume.

window.onload = function() {
    // create and initialize a 3D renderer
    var r = new X.renderer3D();
    r.init();

    // create a X.volume
    var volume = new X.volume();

    // Attach the single-file dicom in .NRRD format
    // this works with gzip/gz/raw encoded NRRD files but XTK also supports other
    // formats like MGH/MGZ
    volume.file = '1123_N3.nii.gz';

    // we also attach a label map to show segmentations on a slice-by-slice base
    // volume.labelmap.file = '1123_seg.nii.gz';

    // add the volume
    r.add(volume);

    // the onShowtime method gets executed after all files were fully loaded and just before the first rendering attempt
    r.onShowtime = function() {
        //
        // The GUI panel
        //
        // (we need to create this during onShowtime(..) since we do not know the
        // volume dimensions before the loading was completed)
        var gui = new dat.GUI();

        // the following configures the gui for interacting with the X.volume
        var volumegui = gui.addFolder('Volume');

        // now we can configure controllers which switch between slicing and volume rendering
        var vrController = volumegui.add(volume, 'volumeRendering');

        // configure the volume rendering opacity
        var opacityController = volumegui.add(volume, 'opacity', 0, 1).listen();

        // and the threshold in the min..max range
        var lowerThresholdController = volumegui.add(volume, 'lowerThreshold', volume.min, volume.max);
        var upperThresholdController = volumegui.add(volume, 'upperThreshold', volume.min, volume.max);

        // the indexX,Y,Z are the currently displayed slice indices in the range [0 - (dimensions-1)]
        var sliceXController = volumegui.add(volume, 'indexX', 0, volume.range[0] - 1);
        var sliceYController = volumegui.add(volume, 'indexY', 0, volume.range[1] - 1);
        var sliceZController = volumegui.add(volume, 'indexZ', 0, volume.range[2] - 1);
        volumegui.open();

        // and this configures the gui for interacting with the label map overlay
        var labelmapgui = gui.addFolder('Label Map');
        var labelMapVisibleController = labelmapgui.add(volume.labelmap, 'visible');
        var labelMapOpacityController = labelmapgui.add(volume.labelmap, 'opacity', 0, 1);
        labelmapgui.open();

    };

    // adjust the camera position a little bit, just for visualization purposes
    r.camera.position = [120, 80, 160];

    // showtime! this triggers the loading of the volume and executes r.onShowtime() once done
    r.render();
};

However if I add the label map to my volume, volume.labelmap.file = '1123_seg.nii.gz';, the loading fails and the volume never shows, see Broken Demo. The only error in the console is the following:

TypeError: b.e.c[0].c[Math.floor(...)] is undefined

Any idea as to what might be wrong? How am I supposed to debug such errors?


Solution

  • Javascript libraries like this are usually minified for production ready versions. It's nearly impossible to debug minified javascript code, but you can see one of the method names in the callstack is .parse, which indicates right away that it's having an issue parsing your labelmap file.

    Most javascript libraries will also include a -debug version that is not minified. I can't seem to find one for xtk, but here's the process for creating a debug version for yourself:

    1. Clone the latest xtk project:

      git clone https://github.com/xtk/X.git

    2. Update google closure (the source is not included):

      cd X/lib/
      git clone https://github.com/google/closure-library
      mv closure-library google-closure-library

    3. I created a demo.html file in the X directory, but you can probably put it anywhere and set it up like:

      <script src="lib/google-closure-library/closure/goog/base.js"></script> <script src="xtk-deps.js"></script>
      <script> goog.require("X"); goog.require("X.renderer3D"); </script>
      <script type="text/javascript" src="demo.js"></script>

    Now you can debug, and you should see your error:

    Uncaught TypeError: Cannot read property '_texture' of undefined parser.js:1205
    X.parser.reslice parser.js:1205
    X.parserNII.parse parserNII.js:258
    (anonymous function)
    

    From here you should be able to hunt down your issue. Looks like a texture is missing.