Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatibility with Cornerstone3D #48

Open
kousu opened this issue Oct 6, 2022 · 10 comments
Open

Compatibility with Cornerstone3D #48

kousu opened this issue Oct 6, 2022 · 10 comments

Comments

@kousu
Copy link

kousu commented Oct 6, 2022

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 cornerstonejs/cornerstone3D#118 (comment), 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

    /*! cornerstone-core - 2.0.0 - 2017-12-14 | (c) 2016 Chris Hafey | https://github.com/cornerstonejs/cornerstone */

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

@kousu
Copy link
Author

kousu commented Oct 7, 2022

(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)

@simonalo
Copy link

simonalo commented Oct 7, 2022

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.

@acegank
Copy link

acegank commented Oct 9, 2022

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

are you have some examples?

@kousu
Copy link
Author

kousu commented Oct 9, 2022

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
Copy link
Author

kousu commented Oct 9, 2022

@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.

@scandel
Copy link

scandel commented Jan 17, 2023

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();

@MYWpro
Copy link

MYWpro commented Feb 4, 2023

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?

@pcanas
Copy link

pcanas commented May 16, 2023

Is this something planned to be tackled soon?

@Ladon90
Copy link

Ladon90 commented May 25, 2023

@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

@ShilpaP17
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants