cornerstone-nifti-image-loader icon indicating copy to clipboard operation
cornerstone-nifti-image-loader copied to clipboard

Compatibility with Cornerstone3D

Open kousu opened this issue 2 years ago • 10 comments

I want to use this but I don't know how I am supposed to right now. Can you clarify if this is/isn't compatible with the new Cornerstone3D? package.json doesn't list it as a dependency (peer or otherwise) so I'm not sure what version of Cornerstone I'm supposed to be using.

According to https://www.cornerstonejs.org/, Cornerstone3D, or @cornerstonejs/core, is the new "beta" version of Cornerstone:

Screenshot_20221006_175839

and according to https://github.com/cornerstonejs/cornerstone3D-beta/issues/118#issuecomment-1270731312, the legacy Cornerstone, cornerstone-core, is no longer being maintained at all.

The two projects have separate versioning schemes. The legacy one is at 2.6.1, the beta is at 0.16.7. So they really are separate projects.

The reason I'm confused is:

  • this repo is installable as @cornerstonejs/nifiti-image-loader, in the same @cornerstonejs group, as if it's a peer of @cornerstonejs/core, and that copy has the most recent 1.0.7 release

  • but it's also installable as the older name cornerstone-nifiti-image-loader, but that copy hasn't been updated since 1.0.0, so that copy is probably dead

  • but the actual examples that show me how to use this in practice have vendored a copy of the legacy code, and haven't touched it in 5 years

    https://github.com/cornerstonejs/cornerstone-nifti-image-loader/blob/b14ae74537d56ea17a282350490949c77512d71f/examples/cornerstone.js#L1

So, how do I use this? If I npm i @cornerstone/core will this work correctly with it?

kousu avatar Oct 06 '22 22:10 kousu

(I do plan to try to test and figure this out on my own. I'm posting this to ask for some guidance to be added to the docs to help others out during the transition)

kousu avatar Oct 07 '22 00:10 kousu

I'm currently trying to make this project work with cornerstone3D but there are functions which changed with corenerstone3D (as loadAndCacheImage for example). I don't know if the both are compatible.

simonalo avatar Oct 07 '22 16:10 simonalo

i load nifti files for Cornerstone3D, but it not works.

are you have some examples?

acegank avatar Oct 09 '22 09:10 acegank

I'm currently trying to make this project work with cornerstone3D but there are functions which changed with corenerstone3D (as loadAndCacheImage for example). I don't know if the both are compatible.

Thank you for the clarification! That helps a lot. I'll build on cornerstone-core^2.6.1 + cornerstore-nifti-image-loader then. I feel pretty stupid for not being able to figure that out from the docs, but they are pretty sprawling and I found myself getting lost in them. Thank you for cutting through the noise for me @simonalo.

kousu avatar Oct 09 '22 16:10 kousu

@acegank there's an example right in the repo.

But like I said, and like @simonalo confirmed, these NIfTI examples need to work against cornerstone-core otherwise known as legacy cornerstone; @cornerstonejs/core otherwise known as Cornerstone3D is not yet compatible with NIfTI files.

kousu avatar Oct 09 '22 16:10 kousu

Hello, I managed to make Cornerstone3D (@cornerstonejs/core) and this project (cornerstone-nifti-image-loader) work together, at least in Stack viewports. Now I'm trying to load a NIFTI as a volume in a Volume viewport, but that's another story...

I post the relevant portions of my code, if it can help somenone. It's not minimal, as I wanted to display 3 orientations (x,y,z) of the same image. And I had to tweak a few things (events, metadata), and I'm not quite sure if there are side effects...

package.json

{
  "name": "cornerstone3d-tests",
  "packageManager": "[email protected]",
  "version": "0.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack --watch",
    "start": "webpack serve --open",
    "build": "webpack"
  },
  "devDependencies": {
    "css-loader": "^6.7.3",
    "style-loader": "^3.3.1",
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.1",
    "webpack-dev-server": "^4.11.1"
  },
  "dependencies": {
    "@cornerstonejs/core": "^0.25.1",
    "@cornerstonejs/nifti-image-loader": "^1.0.9",
    "@cornerstonejs/tools": "^0.35.0",
    "@kitware/vtk.js": "^26.0.0",
    "d3-array": "^3.2.1",
    "d3-interpolate": "^3.0.1",
    "gl-matrix": "^3.4.3"
  }
}

index.js:

import * as cornerstone from '@cornerstonejs/core';
import * as cornerstoneNIFTIImageLoader from '@cornerstonejs/nifti-image-loader';

const { ViewportType } = cornerstone.Enums;

function createElement( size = '400px') {
  let element = document.createElement('div');
  element.style.width = size;
  element.style.height = size;
  element.style.border = '1px solid red';
  element.style.margin = '10px';
  // Disable default context menu
  element.oncontextmenu = (e) => e.preventDefault();
  return element;
}

/**
 * Hardcoded metadata provider for NIFTI images, as they don't exist in the old cornerstone module
 * @param type The type of metadata to retrieve
 * @param imageId The imageId of the image to retrieve metadata for. Must start with 'nifti:'
 * @returns {Object} The metadata object
 */
function additionalMetaDataProvider(type, imageId) {
  const colonIndex = imageId.indexOf(':');
  const scheme = imageId.substring(0, colonIndex);
  if (scheme !== 'nifti') return;
  if (type === 'generalSeriesModule') {
    return {
      modality: 'Unknown',
    };
  }
}

/**
 * Uses the NIFTI image loader to fetch metadata of a NIFTI, cache it in cornerstone,
 * and return a list of imageIds for the frames.
 *
 * @returns {string[]} An array of imageIds for instances in the study.
 */
async function createImageIdsAndCacheMetaData(imageId) {
  const colonIndex = imageId.indexOf(':');
  const scheme = imageId.substring(0, colonIndex);
  if (scheme !== 'nifti') {
    console.warn('createImageIdsAndCacheMetaData: imageId must have scheme "nifti". imageId: ', imageId);
    return;
  }

  // Load the image (it will be stored in the cache, and the metadata also)
  const imageIdObject = cornerstoneNIFTIImageLoader.nifti.ImageId.fromURL(imageId);
  const image = await cornerstone.imageLoader.loadAndCacheImage(imageIdObject.url);

  // Get the number of frames from the metadata the image loader provides
  const numberOfFrames = cornerstone.metaData.get('multiFrame', image.imageId).numberOfFrames;
  const imageIds = Array.from(Array(numberOfFrames),
    (_, i) => `nifti:${imageIdObject.filePath}#${imageIdObject.slice.dimension}-${i},t-0`)
  console.log('imageIds', imageIds);

  return imageIds;
}

async function run() {
  // Create elements to render into
  const content = document.getElementById('content');

  content.style.display = 'flex';
  content.style.flexDirection = 'row';

  const element1 = createElement();
  content.appendChild(element1);
  const element2 = createElement();
  content.appendChild(element2);
  const element3 = createElement();
  content.appendChild(element3);

  // Initialize cornerstone and tools
  await cornerstone.init();

  // Create a rendering engine
  const renderingEngineId = 'myRenderingEngine';
  const renderingEngine = new cornerstone.RenderingEngine(renderingEngineId);

  // Create the viewports (of type STACK)
  const viewportInputArray = [
    {
      viewportId: 'X_VIEWPORT',
      type: ViewportType.STACK,
      element: element1,
    },
    {
      viewportId: 'Y_VIEWPORT',
      type: ViewportType.STACK,
      element: element2,
    },
    {
      viewportId: 'Z_VIEWPORT',
      type: ViewportType.STACK,
      element: element3,
    }
  ];
  renderingEngine.setViewports(viewportInputArray);
  const viewportX = renderingEngine.getViewport('X_VIEWPORT');
  const viewportY = renderingEngine.getViewport('Y_VIEWPORT');
  const viewportZ = renderingEngine.getViewport('Z_VIEWPORT');

  // Register the nifti image loader
  cornerstoneNIFTIImageLoader.external.cornerstone = cornerstone;
  // NOTE: This is a hack to get around the fact that the nifti image loader
  // uses the old cornerstone module, and we need to provide it with the
  // new cornerstone module (events = eventTarget).
  cornerstoneNIFTIImageLoader.external.cornerstone.events = cornerstone.eventTarget;
  // cornerstoneNIFTIImageLoader.nifti.streamingMode = true;

  // Register an additional metadata provider for Nifti images (for the generalSeriesModule, not provided by the package)
  cornerstone.metaData.addProvider(
    (type, imageId) => additionalMetaDataProvider(type, imageId),
    1000 // Priority of the NIFTI metadata provider is 10000, so this one is called after
  );

  // Example of a Nifti image, from the web.
  // The number after # is the frame index
  // const imageUrl = 'https://raw.githubusercontent.com/muschellij2/Neurohacking_data/master/BRAINIX/NIfTI/Output_3D_File.nii.gz#10'

  // Will load a local image
  const imageUrl = `data/mni152_2009_256.nii.gz`;

  // Load the image and assign it to the viewport, for each orientation
  const imageIdsZ = await createImageIdsAndCacheMetaData(`nifti:${imageUrl}#z`);
  viewportZ.setStack(imageIdsZ, Math.floor(imageIdsZ.length / 2));
  viewportZ.render();

  const imageIdsY = await createImageIdsAndCacheMetaData(`nifti:${imageUrl}#y`);
  viewportY.setStack(imageIdsY, Math.floor(imageIdsY.length / 2));
  viewportY.render();

  const imageIdsX = await createImageIdsAndCacheMetaData(`nifti:${imageUrl}#x`);
  viewportX.setStack(imageIdsX, Math.floor(imageIdsX.length / 2));
  viewportX.render();
}

run();

scandel avatar Jan 17 '23 13:01 scandel

load a NIFTI as a volume

@scandel
Did you finish the job? I really don't understand the documentation, can I use imagevolume class to do this task directly?

MYWpro avatar Feb 04 '23 07:02 MYWpro

Is this something planned to be tackled soon?

pcanas avatar May 16 '23 18:05 pcanas

@scandel Thank you very much for your contribution and the explanations! Did you meanwhile found a way to load NIFTI into a volume?

Kind regards

Ladon90 avatar May 25 '23 10:05 Ladon90

Yes you can load NIFTI images in cornerstone3D in volume using @cornerstonejs/nifti-volume-loader. I am able to load in react typescript project with webpack

ShilpaP17 avatar May 10 '24 14:05 ShilpaP17