cornerstone3D icon indicating copy to clipboard operation
cornerstone3D copied to clipboard

Cannot destructure property 'pixelRepresentation'

Open zixiCat opened this issue 3 years ago • 5 comments

When I use wadouri in volume type and then invoke volumeLoader.createAndCacheVolume , it will throw this error. Stack type is okay image image

zixiCat avatar Aug 18 '22 06:08 zixiCat

@zixiCat I think you may not add the metadata into the cornerstoneWADOImageLoader.

zhoualibaba avatar Aug 18 '22 13:08 zhoualibaba

you need to add the metadata to cornerstoneWADOImageLoader first before creating a volume

you can use a function similar to this

    cacheMetaData: async function (series) {
      let wadoRsRoot = `${window.location.origin}/dicom-web`;
      const client = new dicomwebClient.api.DICOMwebClient({ url: wadoRsRoot });
      const studyInstanceUID = series["0020000D"]["Value"][0];
      const seriesInstanceUID = series["0020000E"]["Value"][0];
      let instances = await client.retrieveSeriesMetadata({
        studyInstanceUID: studyInstanceUID,
        seriesInstanceUID: seriesInstanceUID,
      });
      const imageIds = instances.map((instanceMetaData) => {
        const SeriesInstanceUID = instanceMetaData["0020000E"].Value[0];
        const SOPInstanceUID = instanceMetaData["00080018"].Value[0];
        const prefix = "wadors:";
        const imageId = `${prefix}${wadoRsRoot}/studies/${studyInstanceUID}/series/${SeriesInstanceUID}/instances/${SOPInstanceUID}/frames/1`;
        cornerstoneWADOImageLoader.wadors.metaDataManager.add(imageId, instanceMetaData);
        return imageId;
      });
      return imageIds;
    },

You can then pass the returned imageIds to createAndCacheVolume.

IbrahimCSAE avatar Aug 25 '22 11:08 IbrahimCSAE

@IbrahimCSAE I mean I want to display local dicom files by using wadouri prefix, not wadors , is there any way to get these UID?(studyInstanceUID, seriesInstanceUID)

zixiCat avatar Aug 27 '22 03:08 zixiCat

I don't know the exact process, but I think that they need to be loaded into memory and parsed first, I don't think you can just pass the disk location of the file to the function

IbrahimCSAE avatar Aug 28 '22 01:08 IbrahimCSAE

I've used this method before and it didn't work, whether I use "streaming" or not, but thanks

------------------ 原始邮件 ------------------ 发件人: @.>; 发送时间: 2022年8月27日(星期六) 中午1:42 收件人: @.>; 抄送: @.>; @.>; 主题: Re: [cornerstonejs/cornerstone3D-beta] Cannot destructure property 'pixelRepresentation' (Issue #180)

@IbrahimCSAE I mean I want to display local dicom files by using wadouri prefix, not wadors , is there any way to get these UID?(studyInstanceUID, seriesInstanceUID)

You might need to do something like this this let imageIds = [] let imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add(file); imageIds.push(imageId)

then you pass that array of imageIds to the volumeLoader, and try making the scheme 'wadouri' without the word streaming.

I didn't try this so I'm not sure if it will work, I usually don't work with local dicoms. If you can post your code here I can try to modify it and make it work.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>

zixiCat avatar Oct 11 '22 08:10 zixiCat

Hey, I have the same problem but in production, in my local i don't have this problem.

here I call my custom method createImageIdsAndCacheMetaData

  await initProviders();
  await initCornerstoneWADOImageLoader()
  await initVolumeLoader()
  await cornerstone3D.init();
  await cornerstone3DTools.init();




  const imageIds = await createImageIdsAndCacheMetaData({
    StudyInstanceUID: caseId,
    SeriesInstanceUID: imageId,
    wadoRsRoot: process.env.REACT_APP_WADO_RS_ROOT,
    type: 'VOLUME',
  });


  // Define a volume in memory
  const volume = await volumeLoader.createAndCacheVolume(volumeId, {
    imageIds,
  });

and in that method I insert the metadata:

const client = new api.DICOMwebClient({ url: wadoRsRoot });
  const instances = await client.retrieveSeriesMetadata(studySearchOptions);
  const modality = instances[0][MODALITY].Value[0];

  const imageIds = instances.map((instanceMetaData) => {
    const SeriesInstanceUID = instanceMetaData[SERIES_INSTANCE_UID].Value[0];
    const SOPInstanceUID = instanceMetaData[SOP_INSTANCE_UID].Value[0];
    const prefix = type === VOLUME ? 'streaming-wadors:' : 'wadors:';

    const imageId =
      prefix +
      wadoRsRoot +
      '/studies/' +
      StudyInstanceUID +
      '/series/' +
      SeriesInstanceUID +
      '/instances/' +
      SOPInstanceUID +
      '/frames/1';

    cornerstoneWADOImageLoader.wadors.metaDataManager.add(
      imageId,
      instanceMetaData
    );

    WADORSHeaderProvider.addInstance(imageId, instanceMetaData);

    // Add calibrated pixel spacing
    const m = JSON.parse(JSON.stringify(instanceMetaData));
    const instance = DicomMetaDictionary.naturalizeDataset(m);
    const pixelSpacing = getPixelSpacingInformation(instance);

    calibratedPixelSpacingMetadataProvider.add(
      imageId,
      pixelSpacing.map((s) => parseFloat(s))
    );

    return imageId;
  });
  

idk if it's a cache thing because in my local server works but in production this messages jumps out 😢

JwRicauter avatar Oct 21 '22 09:10 JwRicauter

Hey, I have the same problem but in production, in my local i don't have this problem.

here I call my custom method createImageIdsAndCacheMetaData

  await initProviders();
  await initCornerstoneWADOImageLoader()
  await initVolumeLoader()
  await cornerstone3D.init();
  await cornerstone3DTools.init();




  const imageIds = await createImageIdsAndCacheMetaData({
    StudyInstanceUID: caseId,
    SeriesInstanceUID: imageId,
    wadoRsRoot: process.env.REACT_APP_WADO_RS_ROOT,
    type: 'VOLUME',
  });


  // Define a volume in memory
  const volume = await volumeLoader.createAndCacheVolume(volumeId, {
    imageIds,
  });

and in that method I insert the metadata:

const client = new api.DICOMwebClient({ url: wadoRsRoot });
  const instances = await client.retrieveSeriesMetadata(studySearchOptions);
  const modality = instances[0][MODALITY].Value[0];

  const imageIds = instances.map((instanceMetaData) => {
    const SeriesInstanceUID = instanceMetaData[SERIES_INSTANCE_UID].Value[0];
    const SOPInstanceUID = instanceMetaData[SOP_INSTANCE_UID].Value[0];
    const prefix = type === VOLUME ? 'streaming-wadors:' : 'wadors:';

    const imageId =
      prefix +
      wadoRsRoot +
      '/studies/' +
      StudyInstanceUID +
      '/series/' +
      SeriesInstanceUID +
      '/instances/' +
      SOPInstanceUID +
      '/frames/1';

    cornerstoneWADOImageLoader.wadors.metaDataManager.add(
      imageId,
      instanceMetaData
    );

    WADORSHeaderProvider.addInstance(imageId, instanceMetaData);

    // Add calibrated pixel spacing
    const m = JSON.parse(JSON.stringify(instanceMetaData));
    const instance = DicomMetaDictionary.naturalizeDataset(m);
    const pixelSpacing = getPixelSpacingInformation(instance);

    calibratedPixelSpacingMetadataProvider.add(
      imageId,
      pixelSpacing.map((s) => parseFloat(s))
    );

    return imageId;
  });
  

idk if it's a cache thing because in my local server works but in production this messages jumps out 😢

Do u have a demo link where the error pops up?

IbrahimCSAE avatar Oct 21 '22 09:10 IbrahimCSAE

Yes there is a link but is not public yet, I have to give you the credentials.

However, I'm printing the naturalizedDataset variable in WADORSHeaderProvider and print all the metadata variables correctly:

-- Production (with the error) Captura de Pantalla 2022-10-21 a la(s) 12 24 31

-- Same thing in development ( no error ) Captura de Pantalla 2022-10-21 a la(s) 12 25 28

JwRicauter avatar Oct 21 '22 10:10 JwRicauter

Yes there is a link but is not public yet, I have to give you the credentials.

However, I'm printing the naturalizedDataset variable in WADORSHeaderProvider and print all the metadata variables correctly:

-- Production (with the error) Captura de Pantalla 2022-10-21 a la(s) 12 24 31

-- Same thing in development ( no error ) Captura de Pantalla 2022-10-21 a la(s) 12 25 28

in the makeVolumeMetadata.ts file

export default function makeVolumeMetadata(
  imageIds: Array<string>
): Types.Metadata {
  const imageId0 = imageIds[0];

  const {
    pixelRepresentation,
    bitsAllocated,
    bitsStored,
    highBit,
    photometricInterpretation,
    samplesPerPixel,
  } = metaData.get('imagePixelModule', imageId0);

Try placing a breakpoint here, whats the value of imageId0 ? does it match the imageId you created in createImageIdsAndCacheMetaData method?

The only way I see this happening in production and not development is if something causes the ImageIds to be messed up or if the metadataprovider is not being registered

Also the const prefix = type === VOLUME ? 'streaming-wadors:' : 'wadors:';

is there a variable VOLUME defined somewhere? if not it should be 'VOLUME' as a string

IbrahimCSAE avatar Oct 21 '22 10:10 IbrahimCSAE

Yep, it match 😢

this is the first imageId resulting of createImageIdsAndCacheMetaData function

Captura de Pantalla 2022-10-27 a la(s) 9 57 16

and this is the imageIds object of makeVolumeMetadata

Captura de Pantalla 2022-10-27 a la(s) 10 00 03

I will attach the run function, but it's the same of one of the examples.

/*                   -- VOLUME --                  */

const viewportId1 = 'CT_AXIAL';
const viewportId2 = 'CT_SAGITTAL';
const viewportId3 = 'CT_CORONAL';

const viewportColors = {
  [viewportId1]: 'rgb(200, 0, 0)', [viewportId2]: 'rgb(200, 200, 0)', [viewportId3]: 'rgb(0, 200, 0)',
};

const viewportReferenceLineControllable = [
  viewportId1, viewportId2, viewportId3,
];

const viewportReferenceLineDraggableRotatable = [
  viewportId1, viewportId2, viewportId3,
];

const viewportReferenceLineSlabThicknessControlsOn = [
  viewportId1, viewportId2, viewportId3,
];

const getReferenceLineColor = (viewportId) => {
  return viewportColors[viewportId];
}

const getReferenceLineControllable = (viewportId) => {
  const index = viewportReferenceLineControllable.indexOf(viewportId);
  return index !== -1;
}

const getReferenceLineDraggableRotatable = (viewportId) => {
  const index = viewportReferenceLineDraggableRotatable.indexOf(viewportId);
  return index !== -1;
}

const getReferenceLineSlabThicknessControlsOn = (viewportId) => {
  const index =
    viewportReferenceLineSlabThicknessControlsOn.indexOf(viewportId);
  return index !== -1;
}


const volumeLoaderScheme = 'cornerstoneStreamingImageVolume'; // Loader id which defines which volume loader to use
const ctVolumeName = 'CT_VOLUME_ID'; // Id of the volume less loader prefix
const volumeId = `${volumeLoaderScheme}:${ctVolumeName}`; // VolumeId with loader id + volume id

export const runVolume = async (
  cornerstone3D,
  cornerstone3DTools,
  imageId,
  caseId,
  viewerRef1,
  viewerRef2,
  viewerRef3
) => {

  const {
    CONSTANTS, RenderingEngine, setVolumesForViewports, volumeLoader, metaData
  } = cornerstone3D;
  const {
    ToolGroupManager, StackScrollMouseWheelTool, CrosshairsTool, Enums: csToolsEnums, WindowLevelTool, PanTool, ZoomTool
  } = cornerstone3DTools;
  
  const { MouseBindings } = csToolsEnums;
  const { ViewportType } = cornerstone3D.Enums;
  const { ORIENTATION } = CONSTANTS;
  const toolGroupId = 'TOOLGROUP_ID';



  await initProviders();
  await initCornerstoneWADOImageLoader()
  await initVolumeLoader()
  await cornerstone3D.init();
  await cornerstone3DTools.init();




  const imageIds = await createImageIdsAndCacheMetaData({
    StudyInstanceUID: caseId,
    SeriesInstanceUID: imageId,
    wadoRsRoot: process.env.REACT_APP_WADO_RS_ROOT,
    type: 'VOLUME',
  });


  // Define a volume in memory
  const volume = await volumeLoader.createAndCacheVolume(volumeId, {
    imageIds,
  });

  // Instantiate a rendering engine
  const renderingEngineId = 'myRenderingEngine';
  const renderingEngine = new RenderingEngine(renderingEngineId);

  // Create the viewports
  if (
    viewerRef1.current && viewerRef2.current && viewerRef3.current
  ) {
    const viewportInputArray = [
      {
        viewportId: viewportId1,
        type: ViewportType.ORTHOGRAPHIC,
        element: viewerRef1.current,
        defaultOptions: {
          orientation: ORIENTATION.AXIAL,
          background: [0, 0, 0],
        },
      },
      {
        viewportId: viewportId2,
        type: ViewportType.ORTHOGRAPHIC,
        element: viewerRef2.current,
        defaultOptions: {
          orientation: ORIENTATION.SAGITTAL,
          background: [0, 0, 0],
        },
      },
      {
        viewportId: viewportId3,
        type: ViewportType.ORTHOGRAPHIC,
        element: viewerRef3.current,
        defaultOptions: {
          orientation: ORIENTATION.CORONAL,
          background: [0, 0, 0],
        },
      },
    ];
  
    renderingEngine.setViewports(viewportInputArray);
  }


  // Set the volume to load
  volume.load();

  // Set volumes on the viewports
  await setVolumesForViewports(
    renderingEngine,
    [
      {
        volumeId,
        callback: setCtTransferFunctionForVolumeActor,
      },
    ],
    [viewportId1, viewportId2, viewportId3]
  );

  
  let toolGroup = ToolGroupManager.getToolGroup(toolGroupId);
  if (!toolGroup) { 
    toolGroup =  ToolGroupManager.createToolGroup(toolGroupId); 
  }
  // For the crosshairs to operate, the viewports must currently be
  // added ahead of setting the tool active. This will be improved in the future.
  toolGroup.addViewport(viewportId1, renderingEngineId);
  toolGroup.addViewport(viewportId2, renderingEngineId);
  toolGroup.addViewport(viewportId3, renderingEngineId);

  // Manipulation Tools
  toolGroup.addTool(StackScrollMouseWheelTool.toolName);
  toolGroup.addTool(WindowLevelTool.toolName);
  toolGroup.addTool(PanTool.toolName);
  toolGroup.addTool(ZoomTool.toolName);

  // Add Crosshairs tool and configure it to link the three viewports
  // These viewports could use different tool groups. See the PET-CT example
  // for a more complicated used case.
  toolGroup.addTool(CrosshairsTool.toolName, {
    getReferenceLineColor,
    getReferenceLineControllable,
    getReferenceLineDraggableRotatable,
    getReferenceLineSlabThicknessControlsOn,
  });

  toolGroup?.setToolActive(CrosshairsTool.toolName, {
    bindings: [{ mouseButton: MouseBindings.Primary }],
  });
  // As the Stack Scroll mouse wheel is a tool using the `mouseWheelCallback`
  // hook instead of mouse buttons, it does not need to assign any mouse button.
  toolGroup?.setToolActive(StackScrollMouseWheelTool.toolName);

  // Render the image
  await renderingEngine.renderViewports([viewportId1, viewportId2, viewportId3]);
}

JwRicauter avatar Oct 27 '22 13:10 JwRicauter

I mean I want to display local dicom files by using wadouri prefix, not wadors , is there any way to get these UID?(studyInstanceUID, seriesInstanceUID)

WADO-URI or just "DICOM Part 10 over HTTP" isn't supported out the of box by the Cornerstone3D libraries.

You need to use a WADO-RS compliant endpoint to fetch the metadata ahead of time, and then WADO-RS retrieve frames for the URLs.

Or you could write your own loader for all of this, but its not recommended for MPR for the reasons outlined here.

JamesAPetts avatar Oct 31 '22 10:10 JamesAPetts