feat: overlapping segments (#4849)
This commit is contained in:
1 parent
5a6c2aeed9
commit
55d6393a3f
13 files changed
+232
-248
No files matched your search
@@ -46,8 +46,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^3.7.0",
|
||||
"@cornerstonejs/core": "^3.7.0",
|
||||
"@cornerstonejs/adapters": "^3.7.1",
|
||||
"@cornerstonejs/core": "^3.7.1",
|
||||
"@kitware/vtk.js": "32.12.0",
|
||||
"react-color": "^2.19.3"
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^3.7.0",
|
||||
"@cornerstonejs/core": "^3.7.0",
|
||||
"@cornerstonejs/adapters": "^3.7.1",
|
||||
"@cornerstonejs/core": "^3.7.1",
|
||||
"@kitware/vtk.js": "32.12.0",
|
||||
"react-color": "^2.19.3"
|
||||
}
|
||||
|
||||
@@ -182,7 +182,6 @@ async function _loadSegments({
|
||||
|
||||
// Todo: what should be defaults here
|
||||
const tolerance = 0.001;
|
||||
const skipOverlapping = true;
|
||||
eventTarget.addEventListener(Enums.Events.SEGMENTATION_LOAD_PROGRESS, evt => {
|
||||
const { percentComplete } = evt.detail;
|
||||
segmentationService._broadcastEvent(segmentationService.EVENTS.SEGMENT_LOADING_COMPLETE, {
|
||||
@@ -190,11 +189,10 @@ async function _loadSegments({
|
||||
});
|
||||
});
|
||||
|
||||
const results = await adaptersSEG.Cornerstone3D.Segmentation.generateToolState(
|
||||
const results = await adaptersSEG.Cornerstone3D.Segmentation.createFromDICOMSegBuffer(
|
||||
imageIds,
|
||||
arrayBuffer,
|
||||
metaData,
|
||||
{ skipOverlapping, tolerance, eventTarget, triggerEvent }
|
||||
{ metadataProvider: metaData, tolerance }
|
||||
);
|
||||
|
||||
let usedRecommendedDisplayCIELabValue = true;
|
||||
@@ -211,15 +209,6 @@ async function _loadSegments({
|
||||
}
|
||||
});
|
||||
|
||||
if (results.overlappingSegments) {
|
||||
uiNotificationService.show({
|
||||
title: 'Overlapping Segments',
|
||||
message:
|
||||
'Unsupported overlapping segments detected, segmentation rendering results may be incorrect.',
|
||||
type: 'warning',
|
||||
});
|
||||
}
|
||||
|
||||
if (!usedRecommendedDisplayCIELabValue) {
|
||||
// Display a notification about the non-utilization of RecommendedDisplayCIELabValue
|
||||
uiNotificationService.show({
|
||||
|
||||
@@ -46,9 +46,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^3.7.0",
|
||||
"@cornerstonejs/core": "^3.7.0",
|
||||
"@cornerstonejs/tools": "^3.7.0",
|
||||
"@cornerstonejs/adapters": "^3.7.1",
|
||||
"@cornerstonejs/core": "^3.7.1",
|
||||
"@cornerstonejs/tools": "^3.7.1",
|
||||
"classnames": "^2.3.2"
|
||||
}
|
||||
}
|
||||
@@ -42,8 +42,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/core": "^3.7.0",
|
||||
"@cornerstonejs/tools": "^3.7.0",
|
||||
"@cornerstonejs/core": "^3.7.1",
|
||||
"@cornerstonejs/tools": "^3.7.1",
|
||||
"classnames": "^2.3.2"
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.0",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.1",
|
||||
"@ohif/core": "3.10.0-beta.128",
|
||||
"@ohif/ui": "3.10.0-beta.128",
|
||||
"dcmjs": "*",
|
||||
@@ -51,11 +51,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^3.7.0",
|
||||
"@cornerstonejs/core": "^3.7.0",
|
||||
"@cornerstonejs/labelmap-interpolation": "^3.7.0",
|
||||
"@cornerstonejs/polymorphic-segmentation": "^3.7.0",
|
||||
"@cornerstonejs/tools": "^3.7.0",
|
||||
"@cornerstonejs/adapters": "^3.7.1",
|
||||
"@cornerstonejs/core": "^3.7.1",
|
||||
"@cornerstonejs/labelmap-interpolation": "^3.7.1",
|
||||
"@cornerstonejs/polymorphic-segmentation": "^3.7.1",
|
||||
"@cornerstonejs/tools": "^3.7.1",
|
||||
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
|
||||
"@kitware/vtk.js": "32.12.0",
|
||||
"html2canvas": "^1.4.1",
|
||||
|
||||
@@ -391,13 +391,13 @@ class SegmentationService extends PubSubService {
|
||||
): Promise<string> {
|
||||
const { type } = options;
|
||||
let { segmentationId } = options;
|
||||
const { labelmapBufferArray } = segDisplaySet;
|
||||
const { labelMapImages } = segDisplaySet;
|
||||
|
||||
if (type !== LABELMAP) {
|
||||
throw new Error('Only labelmap type is supported for SEG display sets right now');
|
||||
}
|
||||
|
||||
if (!labelmapBufferArray) {
|
||||
if (!labelMapImages || !labelMapImages.length) {
|
||||
throw new Error('SEG reading failed');
|
||||
}
|
||||
|
||||
@@ -414,16 +414,32 @@ class SegmentationService extends PubSubService {
|
||||
}
|
||||
|
||||
const imageIds = images.map(image => image.imageId);
|
||||
const derivedImages = labelMapImages?.flat();
|
||||
const derivedImageIds = derivedImages.map(image => image.imageId);
|
||||
|
||||
const derivedSegmentationImages = await imageLoader.createAndCacheDerivedLabelmapImages(
|
||||
imageIds as string[]
|
||||
);
|
||||
|
||||
segDisplaySet.images = derivedSegmentationImages.map(image => ({
|
||||
segDisplaySet.images = derivedImages.map(image => ({
|
||||
...image,
|
||||
...metaData.get('instance', image.referencedImageId),
|
||||
}));
|
||||
|
||||
// We should parse the segmentation as separate slices to support overlapping segments.
|
||||
// This parsing should occur in the CornerstoneJS library adapters.
|
||||
// For now, we use the volume returned from the library and chop it here.
|
||||
let firstSegmentedSliceImageId = null;
|
||||
for (let i = 0; i < derivedImages.length; i++) {
|
||||
const voxelManager = derivedImages[i].voxelManager as csTypes.IVoxelManager<number>;
|
||||
const scalarData = voxelManager.getScalarData();
|
||||
voxelManager.setScalarData(scalarData);
|
||||
|
||||
// Check if this slice has any non-zero voxels and we haven't found one yet
|
||||
if (!firstSegmentedSliceImageId && scalarData.some(value => value !== 0)) {
|
||||
firstSegmentedSliceImageId = derivedImages[i].referencedImageId;
|
||||
}
|
||||
}
|
||||
|
||||
// assign the first non zero voxel image id to the segDisplaySet
|
||||
segDisplaySet.firstSegmentedSliceImageId = firstSegmentedSliceImageId;
|
||||
|
||||
const segmentsInfo = segDisplaySet.segMetadata.data;
|
||||
|
||||
const segments: { [segmentIndex: string]: cstTypes.Segment } = {};
|
||||
@@ -481,30 +497,6 @@ class SegmentationService extends PubSubService {
|
||||
addColorLUT(colorLUT, colorLUTIndex);
|
||||
this._segmentationIdToColorLUTIndexMap.set(segmentationId, colorLUTIndex);
|
||||
|
||||
// now we need to chop the volume array into chunks and set the scalar data for each derived segmentation image
|
||||
const volumeScalarData = new Uint8Array(labelmapBufferArray[0]);
|
||||
|
||||
// We should parse the segmentation as separate slices to support overlapping segments.
|
||||
// This parsing should occur in the CornerstoneJS library adapters.
|
||||
// For now, we use the volume returned from the library and chop it here.
|
||||
let firstSegmentedSliceImageId = null;
|
||||
for (let i = 0; i < derivedSegmentationImages.length; i++) {
|
||||
const voxelManager = derivedSegmentationImages[i]
|
||||
.voxelManager as csTypes.IVoxelManager<number>;
|
||||
const scalarData = voxelManager.getScalarData();
|
||||
const sliceData = volumeScalarData.slice(i * scalarData.length, (i + 1) * scalarData.length);
|
||||
scalarData.set(sliceData);
|
||||
voxelManager.setScalarData(scalarData);
|
||||
|
||||
// Check if this slice has any non-zero voxels and we haven't found one yet
|
||||
if (!firstSegmentedSliceImageId && sliceData.some(value => value !== 0)) {
|
||||
firstSegmentedSliceImageId = derivedSegmentationImages[i].referencedImageId;
|
||||
}
|
||||
}
|
||||
|
||||
// assign the first non zero voxel image id to the segDisplaySet
|
||||
segDisplaySet.firstSegmentedSliceImageId = firstSegmentedSliceImageId;
|
||||
|
||||
this._broadcastEvent(EVENTS.SEGMENTATION_LOADING_COMPLETE, {
|
||||
segmentationId,
|
||||
segDisplaySet,
|
||||
@@ -515,7 +507,7 @@ class SegmentationService extends PubSubService {
|
||||
representation: {
|
||||
type: LABELMAP,
|
||||
data: {
|
||||
imageIds: derivedSegmentationImages.map(image => image.imageId),
|
||||
imageIds: derivedImageIds,
|
||||
referencedVolumeId: this._getVolumeIdForDisplaySet(referencedDisplaySet),
|
||||
referencedImageIds: imageIds as string[],
|
||||
},
|
||||
@@ -1163,8 +1155,8 @@ class SegmentationService extends PubSubService {
|
||||
highlightFunctionType = 'ease-in-out' // todo: make animation functions configurable from outside
|
||||
): void {
|
||||
const center = this._getSegmentCenter(segmentationId, segmentIndex);
|
||||
|
||||
if (!center) {
|
||||
console.warn('No center found for segmentation', segmentationId, segmentIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
"start": "yarn run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cornerstonejs/core": "^3.7.0",
|
||||
"@cornerstonejs/tools": "^3.7.0",
|
||||
"@cornerstonejs/core": "^3.7.1",
|
||||
"@cornerstonejs/tools": "^3.7.1",
|
||||
"@ohif/core": "3.10.0-beta.128",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.128",
|
||||
"@ohif/extension-default": "3.10.0-beta.128",
|
||||
|
||||
Reference in new issue
Block a user