cornerstonejs / cornerstone3D

Cornerstone is a set of JavaScript libraries that can be used to build web-based medical imaging applications. It provides a framework to build radiology applications such as the OHIF Viewer.
https://cornerstonejs.org
MIT License
590 stars 302 forks source link

[Bug] segmentation mismatch on mpr view #1188

Open l5769389 opened 7 months ago

l5769389 commented 7 months ago

Describe the Bug

When I use the demo data of ohif-view segment to generate MPR images, it seems that the results are not consistent with the display in ohif-view. The following issues have occurred: 1. Vertical lines appear in the image; 2. The 10th image in the sagittal view displays incorrect segment information. 图片 here is my code:

const start = async () => {
  await initDemo()
  initTools()
  await createVolume()
  await loadSegmentation()
  await initRender()
}
const createVolume = async () => {
  volume = await volumeLoader.createAndCacheVolume(volumeId, {
    imageIds: imageIdsRef.value
  })
}
const segmentBufferRef = ref()
watchEffect(async () => {
  if (querySegParams.value.sopInstanceUID) {
    segmentBufferRef.value = await retrieveDicomData(querySegParams.value)
  }
})

const loadSegmentation = async () => {
  const arrayBuffer = segmentBufferRef.value
  const generateToolState = await adaptersSEG.Cornerstone3D.Segmentation.generateToolState(
    imageIdsRef.value,
    arrayBuffer,
    metaData
  )
  updateSegDetail(generateToolState)

  const derivedVolume = await addSegmentationsToState()
  const derivedVolumeScalarData = derivedVolume.getScalarData()
  derivedVolumeScalarData.set(new Uint8Array(generateToolState.labelmapBufferArray[0]))
}

async function addSegmentationsToState() {
  const segmentationVolume = await volumeLoader.createAndCacheDerivedSegmentationVolume(volumeId, {
    volumeId: segmentationId
  })
  segmentation.addSegmentations([
    {
      segmentationId: segmentationId,
      representation: {
        type: csToolsEnums.SegmentationRepresentations.Labelmap,
        data: {
          volumeId: segmentationId
        }
      }
    }
  ])
  // Add the segmentation representation to the toolgroup
  const segmentationRepresentationUIDs = await segmentation.addSegmentationRepresentations(toolGroupId, [
    {
      segmentationId,
      type: csToolsEnums.SegmentationRepresentations.Labelmap
    }
  ])
  segmentationRepresentationUID = segmentationRepresentationUIDs[0]
  return segmentationVolume
}

const initRender = async () => {
  renderingEngine = new RenderingEngine(renderingEngineId)
  const viewportInputArray: any = [
    {
      viewportId: viewportId1,
      type: ViewportType.ORTHOGRAPHIC,
      element: axRef.value[0],
      defaultOptions: {
        orientation: Enums.OrientationAxis.AXIAL,
        background: <Types.Point3>[0, 0, 0]
      }
    },
    {
      viewportId: viewportId2,
      type: ViewportType.ORTHOGRAPHIC,
      element: sagRef.value[0],
      defaultOptions: {
        orientation: Enums.OrientationAxis.SAGITTAL,
        background: <Types.Point3>[0, 0, 0]
      }
    },
    {
      viewportId: viewportId3,
      type: ViewportType.ORTHOGRAPHIC,
      element: corRef.value[0],
      defaultOptions: {
        orientation: Enums.OrientationAxis.CORONAL,
        background: <Types.Point3>[0, 0, 0]
      }
    },
    {
      viewportId: viewportId4,
      type: ViewportType.VOLUME_3D,
      element: surfaceRenderRef.value[0],
      defaultOptions: {
        // background: <Types.Point3>[0.2, 0, 0.2]
      }
    }
  ]
  renderingEngine.setViewports(viewportInputArray)
  toolGroup.addViewport(viewportId2, renderingEngineId)
  volume.load()
  await setVolumesForViewports(renderingEngine, [{ volumeId }], [viewportId1, viewportId2, viewportId3, viewportId4])
  const viewport3d = renderingEngine.getViewport(viewportId4)
  const volumeActor = viewport3d.getDefaultActor().actor as Types.VolumeActor
  utilities.applyPreset(
    volumeActor,
    CONSTANTS.VIEWPORT_PRESETS.find((preset) => preset.name === 'CT-AAA') as any
  )
  const renderer = viewport3d.getRenderer()
  renderer.getActiveCamera().elevation(-70)
  viewport3d.setCamera({ parallelScale: 300 })
  renderingEngine.renderViewports([viewportId2])
}

Is it because I'm displaying the MPR view while the ohif-view official demo is using the stack view?

Steps to Reproduce

here is my package.json:

    "@cornerstonejs/adapters": "^1.68.1",
    "@cornerstonejs/calculate-suv": "^1.1.0",
    "@cornerstonejs/core": "^1.68.1",
    "@cornerstonejs/dicom-image-loader": "^1.68.1",
    "@cornerstonejs/streaming-image-volume-loader": "^1.68.1",
    "@cornerstonejs/tools": "^1.68.1",
    "@electron-toolkit/preload": "^3.0.0",
    "@electron-toolkit/utils": "^3.0.0",
    "@kitware/vtk.js": "^29.7.0",
    "dcmjs": "^0.30.1",
    "electron": "^28.2.0",

node version: v16.13.0

The current behavior

show error

The expected behavior

like ohif-view: https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046

OS

window11

Node version

v16.13.0

Browser

"electron": "^28.2.0",

l5769389 commented 7 months ago

this is the way i get segmentation data:

async function retrieveDicomData({ studyInstanceUID, seriesInstanceUID, sopInstanceUID, wadoRsRoot }) {
  const client = new api.DICOMwebClient({
    url: wadoRsRoot as string,
    singlepart: true,
    headers: PACS_SETTING.OpenAuth ? {
      'Authorization': 'Basic ' + btoa(PACS_SETTING.username + ':' + PACS_SETTING.password)
    } : {}
  })
  const options = {
    studyInstanceUID,
    seriesInstanceUID,
    sopInstanceUID
  }
  return await client.retrieveInstance(options)
}
prerakmody commented 5 months ago

Hi, I too noticed this (see here - Load "C3D - MR + RTSS").

Were you able to resolve this?

sedghi commented 4 months ago

I'm wondering how OHIF works fine

CleanShot 2024-07-05 at 14 10 58@2x

If OHIF works and not cornerstone, then it is the metadata problem always

sedghi commented 1 week ago

Does this work in latest OHIF release 3.9?