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

[Bug] how to load dicom-segment data #1170

Closed
l5769389 opened this issue Mar 25, 2024 · 24 comments · May be fixed by #1305
Closed

[Bug] how to load dicom-segment data #1170

l5769389 opened this issue Mar 25, 2024 · 24 comments · May be fixed by #1305

Comments

@l5769389
Copy link

Describe the Bug

图片
the img is from OHIF Viewer。 how can i use cornerstone3D to load the dicom-segment。 or like the export demo can i load the exported file?

Steps to Reproduce

like above

The current behavior

like above

The expected behavior

like above

OS

window11

Node version

18

Browser

chrome

@jlopes90
Copy link
Contributor

jlopes90 commented Mar 25, 2024

Segmentation Volume #664
Segmentation Stack #1059

@l5769389
Copy link
Author

Segmentation Volume #664 Segmentation Stack #1059
The link you provided doesn't seem to fully solve the issue. I couldn't understand the code in OHIF-VIEWER, it's too complex. Are there any simpler examples?

@jlopes90
Copy link
Contributor

jlopes90 commented Mar 25, 2024

How import Segmentation Volume #664 (comment)

Edited (27/03/2024)

@l5769389
Copy link
Author

Import Segmentation Volume

const { viewport } = libCornerstone.getEnabledElement(element);

await libCornerstone.imageLoader.loadAndCacheImages(imageIds);

const volume = await libCornerstone.volumeLoader.createAndCacheVolume(volumeId, {
    imageIds: imageIds
});

volume.load();

await viewport.setVolumes([{ volumeId }]);

viewport.render();

// "arrayBuffer" is file segmentation dicom
const result = libCornerstone.adapters.segmentation.generateToolState(viewport.imageIds, arrayBuffer);

const derivedVolume = await libCornerstone.volumeLoader.createAndCacheDerivedVolume(volume.volumeId, {
    volumeId: segmentationId
});
const derivedVolumeScalarData = derivedVolume.getScalarData();
derivedVolumeScalarData.set(new Uint8Array(result.labelmapBufferArray[0]));

libCornerstoneTools.segmentation.addSegmentation(segmentationId);
await libCornerstoneTools.segmentation.addSegmentationRepresentation(toolGroupId, segmentationId);

how to get segmentationId?

@jlopes90
Copy link
Contributor

jlopes90 commented Mar 26, 2024

how to get segmentationId?

// It is to create or generate id in segmentation, for example:
const uid = cornerstone.utilities.uuidv4();
const segmentationId = 'segmentation-image-volume:' + uid;

@l5769389
Copy link
Author

l5769389 commented Mar 27, 2024

let me answer the question。demo is base vue 、 offical demo and the data source is i got from ohif-view demo

<script setup lang="ts">
import { getDicomSource } from '@/config/config'
import {
  Enums,
  RenderingEngine,
  Types,
  volumeLoader,
  utilities, setVolumesForViewports
} from '@cornerstonejs/core'
import * as cornerstone from '@cornerstonejs/core'
import { adaptersSEG } from '@cornerstonejs/adapters'
import { metaData } from '@cornerstonejs/core'
import { api } from 'dicomweb-client'
import { onMounted, ref } from 'vue'
import * as cornerstoneTools from '@cornerstonejs/tools'
import { initDemo, createImageIdsAndCacheMetaData } from '@/helpers/index.js'
import { StackScrollMouseWheelTool, ToolGroupManager, SegmentationDisplayTool } from '@cornerstonejs/tools'

const { ViewportType } = Enums
let renderingEngineId = '123'
let volumeId = 'volumeId'
const viewportId = 'viewportId'
let renderingEngine
let imageIds
let volume
let toolGroup
const renderContainerRef = ref(null)
const toolGroupId = 'toolGroupId'
const {
  segmentation,
  Enums: csToolsEnums
} = cornerstoneTools
const uuid = utilities.uuidv4()
const segmentationId = 'segmentation-image-volume:' + uuid

async function getImageIds() {
  const params = getDicomSource()
  // params = {
  //   StudyInstanceUID: "1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046",
  //     SeriesInstanceUID: "1.3.12.2.1107.5.2.32.35162.1999123112191238897317963.0.0.0",
  //   wadoRsRoot: `/dicom-web`
  // };
  imageIds = await createImageIdsAndCacheMetaData(params)
}

async function addSegmentationsToState() {
  const segParams = {
    studyInstanceUID: '1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046',
    seriesInstanceUID: '1.2.276.0.7230010.3.1.3.296485376.8.1542816659.201008',
    sopInstanceUID: '1.2.276.0.7230010.3.1.4.296485376.8.1542816659.201009',
    wadoRsRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb'
  }
  const arrayBuffer = await retrieveDicomData(segParams)
  const result = await adaptersSEG.Cornerstone3D.Segmentation.generateToolState(imageIds, arrayBuffer, metaData)
  const segmentationVolume = await volumeLoader.createAndCacheDerivedSegmentationVolume(volumeId, {
    volumeId: segmentationId
  })
  segmentation.addSegmentations([
    {
      segmentationId: segmentationId,
      representation: {
        // The type of segmentation
        type: csToolsEnums.SegmentationRepresentations.Labelmap,
        // The actual segmentation data, in the case of labelmap this is a
        // reference to the source volume of the segmentation.
        data: {
          volumeId: segmentationId
        }
      }
    }
  ])
  const segmentationVolume1 = cornerstone.cache.getVolume(segmentationVolume.volumeId)
  const scalarData = segmentationVolume1.getScalarData()
  scalarData.set(new Uint8Array(result.labelmapBufferArray[0]))
}

function retrieveDicomData({ studyInstanceUID, seriesInstanceUID, sopInstanceUID, wadoRsRoot }) {
  const client = new api.DICOMwebClient({
    url: wadoRsRoot
  })
  const options = {
    studyInstanceUID,
    seriesInstanceUID,
    sopInstanceUID
  }
  return client.retrieveInstance(options)
}

function render() {
  renderingEngine.renderViewport(viewportId)
}

const initTools = () => {
  cornerstoneTools.addTool(SegmentationDisplayTool)
  toolGroup = ToolGroupManager.createToolGroup(toolGroupId)
  toolGroup.addTool(StackScrollMouseWheelTool.toolName)
  toolGroup.addTool(SegmentationDisplayTool.toolName)

  toolGroup.setToolEnabled(SegmentationDisplayTool.toolName)
  toolGroup.setToolActive(StackScrollMouseWheelTool.toolName)
}

const initRender = async () => {
  renderingEngine = new RenderingEngine(renderingEngineId)
  const viewportInputArray = [{
    viewportId,
    type: ViewportType.ORTHOGRAPHIC,
    element: renderContainerRef.value,
    defaultOptions: {
      orientation: Enums.OrientationAxis.SAGITTAL,
      background: <Types.Point3>[0.2, 0, 0.2]
    }
  }]
  renderingEngine.setViewports(viewportInputArray)
  toolGroup.addViewport(viewportId, renderingEngineId)
  volume.load()
  await setVolumesForViewports(
    renderingEngine,
    [{ volumeId }],
    [viewportId]
  )
  await segmentation.addSegmentationRepresentations(toolGroupId, [
    {
      segmentationId,
      type: csToolsEnums.SegmentationRepresentations.Labelmap
    }
  ])
}

async function createVolume() {
  volume = await volumeLoader.createAndCacheVolume(volumeId, {
    imageIds
  })
}

onMounted(async () => {
  await initDemo()
  initTools()
  await getImageIds()
  await createVolume()
  await addSegmentationsToState()
  await initRender()
  render()
})


</script>

<template>
  <div class="w-full h-[500px] bg-transparent flex justify-center">
    <div class="w-[600px] h-full bg-transparent  relative" ref="renderContainerRef">
    </div>
  </div>
</template>

<style scoped>

</style>

the addSegmentationsToState function is get the segment data and set to display。
and i got metadata get undefined。 i add a provider (you should register it to cornerstone) and save sopIntanceUid to metadata like this:
图片

@jlopes90
Copy link
Contributor

@l5769389

take a look #664 (comment)

@l5769389
Copy link
Author

图片
When I use the official data of ohif-view and run the code listed above, I encounter some mismatched images. I think there might be an issue with the implementation in addSegmentationsToState(). Can anyone help me resolve this?

@l5769389
Copy link
Author

l5769389 commented Apr 7, 2024

@jlopes90 i want to modify the segment render color。 but i dont know how to do. can you show me ? it looks like use the api: i got the segment data like this:

const arrayBuffer = await retrieveDicomData(segParams)
  const result = await adaptersSEG.Cornerstone3D.Segmentation.generateToolState(imageIds, arrayBuffer, metaData)
  const segmentationVolume = await volumeLoader.createAndCacheDerivedSegmentationVolume(volumeId, {
    volumeId: segmentationId
  })

@jlopes90
Copy link
Contributor

jlopes90 commented Apr 8, 2024

@l5769389 https://www.cornerstonejs.org/live-examples/labelmapsegmentcolorchange

This is not in the examples list, I just made a PR #1192

@l5769389
Copy link
Author

l5769389 commented Apr 9, 2024

**@jlopes90 here is the way i get segment arraybuffer from PACS System ,am i right? the segment data need be accurate to sopInstanceUID ?

async function retrieveSegData({ studyInstanceUID, seriesInstanceUID, sopInstanceUID, wadoRsRoot }) {
  const client = new api.DICOMwebClient({
    url: wadoRsRoot as string,
  })
  const options = {
    studyInstanceUID,
    seriesInstanceUID,
    sopInstanceUID
  }
  return await client.retrieveInstance(options)
}
```**

@jlopes90
Copy link
Contributor

jlopes90 commented Apr 9, 2024

@l5769389 I don't know, I've never tried PACS

@l5769389
Copy link
Author

@jlopes90, Sorry to bother you again, but I've been using your segmentation loading demo. I've found a bug when retrieving DICOM data from a remote PACS (Orthanc) via API (similar to the demoDicom() function) and then reading segmentation data locally. In Figure 1, DICOM data is fetched from Orthanc via an API, while segmentation data is read locally using an tag. In Figure 2, both DICOM and segmentation data are read locally using tags. It's evident that there's a bug in Figure 1. Could you please help me resolve this? all use your demo。 i only change the StudyInstanceUID and SeriesInstanceUID from your demo . I believe there might be some flaws in your example.
pacs上获取dicom,本地加载seg
本地读取,本地加载seg

@l5769389
Copy link
Author

@jlopes90
Copy link
Contributor

jlopes90 commented Apr 10, 2024

@l5769389 #1201

Example:
https://deploy-preview-1201--cornerstone-3d-docs.netlify.app/live-examples/segmentationVolume.html

Try editing exConfig in the console or you can make PACS.

exConfig.fetchDicom = {
  "StudyInstanceUID": "1.3.6.1.4.1.14519.5.2.1.256467663913010332776401703474716742458",
  "SeriesInstanceUID": "1.3.6.1.4.1.14519.5.2.1.40445112212390159711541259681923198035",
  "wadoRsRoot": "https://d33do7qe4w26qo.cloudfront.net/dicomweb"
};

exConfig.fetchSegmentation = {
  "StudyInstanceUID": "1.3.6.1.4.1.14519.5.2.1.256467663913010332776401703474716742458",
  "SeriesInstanceUID": "1.2.276.0.7230010.3.1.3.481034752.2667.1663086918.611582",
  "SOPInstanceUID": "1.2.276.0.7230010.3.1.4.481034752.2667.1663086918.611583",
  "wadoRsRoot": "https://d33do7qe4w26qo.cloudfront.net/dicomweb"
};

Run Load DICOM and Load SEG.

Edited (11/04/2024)

@l5769389
Copy link
Author

  1. i tried your demo, Still no effect, just causing the display to flip.
  2. in console set window.exConfig not effect in the link.
    图片
    this is ohif-viewer's config:
const exConfig = {
  fetchDicom: {
    StudyInstanceUID: '1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046',
    SeriesInstanceUID: '1.3.12.2.1107.5.2.32.35162.1999123112191238897317963.0.0.0',
    wadoRsRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb'
  },
  fetchSegmentation: {
    StudyInstanceUID: '1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046',
    SeriesInstanceUID: '1.2.276.0.7230010.3.1.3.296485376.8.1542816659.201008',
    SOPInstanceUID: '1.2.276.0.7230010.3.1.4.296485376.8.1542816659.201009',
    wadoRsRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb'
  }
}

@jlopes90
Copy link
Contributor

jlopes90 commented Apr 11, 2024

Ops sorry. This is the code I have already tested and it is exactly the same as the one above. #1170 (comment)

exConfig.fetchDicom = {
    StudyInstanceUID: '1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046',
    SeriesInstanceUID: '1.3.12.2.1107.5.2.32.35162.1999123112191238897317963.0.0.0',
    wadoRsRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb'
};

exConfig.fetchSegmentation = {
    StudyInstanceUID: '1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046',
    SeriesInstanceUID: '1.2.276.0.7230010.3.1.3.296485376.8.1542816659.201008',
    SOPInstanceUID: '1.2.276.0.7230010.3.1.4.296485376.8.1542816659.201009',
    wadoRsRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb'
};

@l5769389
Copy link
Author

@jlopes90 i copy your demo and tried it again . result seems still error . use the url like above。 you can scroll sag viewer to see the error, it may appear in about index 10/128 or index 118/128 。
图片

@l5769389
Copy link
Author

In the volume view, you can see the errors more clearly. Figure 1 mpr is correct, while Figure 2 shows the error that occurred using Cornerstone. they are same source。
图片
1712887377780

@steph603
Copy link

@l5769389 did you ever resolve your issue with segmentations displaying misaligned? I am having something similar.

@jlopes90 I have implemented your volume segmentation example (thank you - it's an excellent demo!) - The issue is occurring when I swap from loading in a dicom file from my machine to fetching from Orthanc.

When loading the base images from a local dicom, and request segments from Orthanc (or a local file), everything works as expected.
When I swap to obtaining base images from Orthanc, whether segments are local or from Orthanc, the segments are misaligned as below.

I believe something is wrong or lacking when using createImageIdsAndCacheMetaData for the base images.
Is there another way I can get those base images loaded in that would more closely replicate using a file, like retrieveInstance which works well for segmentations?

Screenshot 2024-05-14 at 3 40 55 PM

@l5769389
Copy link
Author

@steph603 I didn't find a solution。 Wait for the author to solve this problem

@l5769389
Copy link
Author

my co-worker now find the solution 。you can test: @steph603 ,but it seems still error in 3d。
a06634b258ab86fda60e1e2ce719c1b
1715912897830

@steph603
Copy link

steph603 commented Jun 5, 2024

Update: We found a solution!

I'm aware of this PR that reversed the image IDs and that did seem to partially help, however, there was still something causing our segmentations to display incorrectly when base images were coming from Orthanc - like so:
image

We discovered that the order of the image ids was being scrambled when retrieving from Orthanc, and while the base images were displaying correctly, segmentations were not aligning.
The solution is to sort the image ids based on the Instance Number (0020,0013)

const sortedInstances = Object.values(instances).sort((a,b) => a['00200013'].Value[0] - b['00200013'].Value[0])

in createImageIdsAndCacheMetaData like this:

image
Now our segments are displaying as expected:

image

@sedghi
Copy link
Member

sedghi commented Jun 6, 2024

I guess i'm gonna close this now that the issue is resolved

@sedghi sedghi closed this as completed Jun 6, 2024
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

Successfully merging a pull request may close this issue.

4 participants