diff --git a/src/io/dicom.ts b/src/io/dicom.ts index b16621cf..28a10f12 100644 --- a/src/io/dicom.ts +++ b/src/io/dicom.ts @@ -4,6 +4,7 @@ import { readDicomTags, readImageDicomFileSeries, readOverlappingSegmentation, + ReadOverlappingSegmentationResult, } from '@itk-wasm/dicom'; import itkConfig from '@/src/io/itk/itkConfig'; @@ -174,12 +175,27 @@ export async function readVolumeSlice( return result.outputs[0].data as Image; } +type Segment = { + SegmentLabel: string; + labelID: number; + recommendedDisplayRGBValue: [number, number, number]; +}; + +type ReadOverlappingSegmentationMeta = { + segmentAttributes: Segment[][]; +}; + +type ReadOverlappingSegmentationResultWithRealMeta = + ReadOverlappingSegmentationResult & { + metaInfo: ReadOverlappingSegmentationMeta; + }; + export async function buildLabelMap(file: File) { const inputImage = sanitizeFile(file); - const result = await readOverlappingSegmentation(inputImage, { + const result = (await readOverlappingSegmentation(inputImage, { webWorker: getWorker(), mergeSegments: true, - }); + })) as ReadOverlappingSegmentationResultWithRealMeta; return { ...result, outputImage: result.segImage, diff --git a/src/store/datasets-dicom.ts b/src/store/datasets-dicom.ts index 773d4efe..fead23cf 100644 --- a/src/store/datasets-dicom.ts +++ b/src/store/datasets-dicom.ts @@ -52,7 +52,7 @@ export interface VolumeInfo { const buildImage = async (seriesFiles: File[], modality: string) => { if (modality === 'SEG') { return { - modality, + modality: 'SEG', builtImageResults: await DICOM.buildLabelMap(seriesFiles[0]), messages: seriesFiles.length > 1 @@ -61,7 +61,6 @@ const buildImage = async (seriesFiles: File[], modality: string) => { }; } return { - modality, builtImageResults: await DICOM.buildImage(seriesFiles), messages: [], }; @@ -75,7 +74,6 @@ const constructImage = async (volumeKey: string, volumeInfo: VolumeInfo) => { const image = vtkITKHelper.convertItkToVtkImage( results.builtImageResults.outputImage ); - debugger; return { ...results, image, diff --git a/src/store/segmentGroups.ts b/src/store/segmentGroups.ts index 53e928bd..abcdc9d2 100644 --- a/src/store/segmentGroups.ts +++ b/src/store/segmentGroups.ts @@ -203,39 +203,31 @@ export const useSegmentGroupStore = defineStore('segmentGroup', () => { delete metadataByID[id]; } - let lastColorIndex = 0; - function getNextColor() { - const color = DEFAULT_SEGMENT_MASKS[lastColorIndex].color; - lastColorIndex = (lastColorIndex + 1) % DEFAULT_SEGMENT_MASKS.length; - return [...color]; - } - - function decodeSegments(image: DataSelection) { - if (isRegularImage(image)) { - return structuredClone(DEFAULT_SEGMENT_MASKS); + // let lastColorIndex = 0; + // function getNextColor() { + // const color = DEFAULT_SEGMENT_MASKS[lastColorIndex].color; + // lastColorIndex = (lastColorIndex + 1) % DEFAULT_SEGMENT_MASKS.length; + // return [...color]; + // } + + async function decodeSegments(image: DataSelection) { + if (!isRegularImage(image)) { + // dicom image + const dicomStore = useDICOMStore(); + + const volumeBuildResults = await dicomStore.volumeBuildResults[image]; + if (volumeBuildResults.modality === 'SEG') { + const segments = + volumeBuildResults.builtImageResults.metaInfo.segmentAttributes[0]; + return segments.map((segment) => ({ + value: segment.labelID, + name: segment.SegmentLabel, + color: [...segment.recommendedDisplayRGBValue, 255], + })); + } } - const dicomStore = useDICOMStore(); - const volumeInfo = dicomStore.volumeInfo[image]; - const segmentSequence = undefined; // volumeInfo.SegmentSequence; - if (!segmentSequence) { - return [ - { - value: 255, - name: volumeInfo.SeriesDescription || 'Unknown Segment', - color: getNextColor(), - }, - ]; - } - // TODO convert Recommended Display CIELab Value (0062,000D) tag to a segment color - // TODO convert SegmentDescription (0062,0006) tag to a segment name - return [ - { - value: 255, - name: volumeInfo.SeriesDescription || 'Unknown Segment', - color: [255, 0, 255, 255], - }, - ]; + return structuredClone(DEFAULT_SEGMENT_MASKS); } /** @@ -269,7 +261,7 @@ export const useSegmentGroupStore = defineStore('segmentGroup', () => { } const name = imageStore.metadata[imageID].name; - // Don't remove image if DICOM as user may have selected child image as primary selection by now + // Don't remove image if DICOM as user may have selected segment group image as primary selection by now const deleteImage = isRegularImage(imageID); if (deleteImage) { imageStore.deleteData(imageID); @@ -282,7 +274,7 @@ export const useSegmentGroupStore = defineStore('segmentGroup', () => { : resampled; const labelmapImage = toLabelMap(ownedMemoryImage); - const segments = decodeSegments(imageID); + const segments = await decodeSegments(imageID); const { order, byKey } = normalizeForStore(segments, 'value'); const segmentGroupStore = useSegmentGroupStore(); segmentGroupStore.addLabelmap(labelmapImage, {