2022-11-16 20:19:52 +01:00
|
|
|
import { utils } from '@ohif/core';
|
2024-11-06 13:15:27 +01:00
|
|
|
import { metaData, triggerEvent, eventTarget } from '@cornerstonejs/core';
|
|
|
|
|
import { CONSTANTS, segmentation as cstSegmentation } from '@cornerstonejs/tools';
|
2023-08-08 20:39:31 +02:00
|
|
|
import { adaptersSEG, Enums } from '@cornerstonejs/adapters';
|
2022-11-16 20:19:52 +01:00
|
|
|
|
|
|
|
|
import { SOPClassHandlerId } from './id';
|
2023-08-08 20:39:31 +02:00
|
|
|
import { dicomlabToRGB } from './utils/dicomlabToRGB';
|
2022-11-16 20:19:52 +01:00
|
|
|
|
|
|
|
|
const sopClassUids = ['1.2.840.10008.5.1.4.1.1.66.4'];
|
|
|
|
|
|
2024-05-08 18:12:49 +02:00
|
|
|
const loadPromises = {};
|
2022-11-16 20:19:52 +01:00
|
|
|
|
2024-05-08 18:12:49 +02:00
|
|
|
function _getDisplaySetsFromSeries(
|
|
|
|
|
instances,
|
|
|
|
|
servicesManager: AppTypes.ServicesManager,
|
|
|
|
|
extensionManager
|
|
|
|
|
) {
|
2022-11-16 20:19:52 +01:00
|
|
|
const instance = instances[0];
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
StudyInstanceUID,
|
|
|
|
|
SeriesInstanceUID,
|
|
|
|
|
SOPInstanceUID,
|
|
|
|
|
SeriesDescription,
|
|
|
|
|
SeriesNumber,
|
|
|
|
|
SeriesDate,
|
|
|
|
|
SOPClassUID,
|
|
|
|
|
wadoRoot,
|
|
|
|
|
wadoUri,
|
|
|
|
|
wadoUriRoot,
|
|
|
|
|
} = instance;
|
|
|
|
|
|
|
|
|
|
const displaySet = {
|
|
|
|
|
Modality: 'SEG',
|
|
|
|
|
loading: false,
|
|
|
|
|
isReconstructable: true, // by default for now since it is a volumetric SEG currently
|
|
|
|
|
displaySetInstanceUID: utils.guid(),
|
|
|
|
|
SeriesDescription,
|
|
|
|
|
SeriesNumber,
|
|
|
|
|
SeriesDate,
|
|
|
|
|
SOPInstanceUID,
|
|
|
|
|
SeriesInstanceUID,
|
|
|
|
|
StudyInstanceUID,
|
|
|
|
|
SOPClassHandlerId,
|
|
|
|
|
SOPClassUID,
|
|
|
|
|
referencedImages: null,
|
|
|
|
|
referencedSeriesInstanceUID: null,
|
|
|
|
|
referencedDisplaySetInstanceUID: null,
|
|
|
|
|
isDerivedDisplaySet: true,
|
|
|
|
|
isLoaded: false,
|
|
|
|
|
isHydrated: false,
|
|
|
|
|
segments: {},
|
|
|
|
|
sopClassUids,
|
|
|
|
|
instance,
|
2023-04-25 23:25:10 +02:00
|
|
|
instances: [instance],
|
2022-11-16 20:19:52 +01:00
|
|
|
wadoRoot,
|
|
|
|
|
wadoUriRoot,
|
|
|
|
|
wadoUri,
|
feat(RT): add dicom RT support via volume viewports (#3310)
* feat: initial RT support
* make the segmentation service work with representation data
* feat: make segmentation service work with representations
* fix rtss vis
* fix: rt hydration
* fix the rendering of rt names
* fix imports
* refactor: Modify status and click handling for hydration of RTStructures
Modify status and click handling for hydration of RTStructures by renaming `onPillClick` to `onStatusClick` in `OHIFCornerstoneRTViewport.tsx` and `_getStatusComponent.tsx` files. Also, update initial segmentation configurations in `PanelSegmentation.tsx` and simplify configuration changes and values for segmentation service in `SegmentationService.ts`. Finally, remove console debug in `CornerstoneViewportService.ts`.
* wip for highlighting contours
* refactor rt displayset code
* review code update
* update cornerstone dependencies
* refactor: Update license year, version number, and minor code cleanup
This commit updates the license year in several files, updates the version number in package.json, and contains minor code cleanup in two files.
* add bulkdataURI retrieve for RT
* fix package version
* apply review comments
* apply review comments
* apply review comments
* feat(panels): refactor and streamline segmentation configuration and inputs
Rewrote state hooks and streamlined the configuration input for `PanelSegmentation` to be more verbose and reusable. Included several new input types, including the `InputRange` component which now shows a fixed floating value based on the step provided. The `SegmentationConfig` component now works with dynamic values controlled by `initialConfig`. These changes should improve function usability and make the code more maintainable going forward.
* fix various bugs
* fix contour delete by upgrade cs3d version
* feat(viewport, inputNumber, segmentationConfig, orthanc): Implement minimum and maximum values for input number components, and useBulkDataURI for Orthanc configuration. Compare measurement view planes with absolute viewport view planes in Cornerstone viewport.
* update yarn lock
2023-04-26 18:21:08 +02:00
|
|
|
isOverlayDisplaySet: true,
|
2022-11-16 20:19:52 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const referencedSeriesSequence = instance.ReferencedSeriesSequence;
|
|
|
|
|
|
|
|
|
|
if (!referencedSeriesSequence) {
|
2023-10-03 16:11:32 +02:00
|
|
|
console.error('ReferencedSeriesSequence is missing for the SEG');
|
|
|
|
|
return;
|
2022-11-16 20:19:52 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-22 16:23:44 +02:00
|
|
|
const referencedSeries = referencedSeriesSequence[0] || referencedSeriesSequence;
|
2022-11-16 20:19:52 +01:00
|
|
|
|
2023-09-01 22:19:39 +02:00
|
|
|
displaySet.referencedImages = instance.ReferencedSeriesSequence.ReferencedInstanceSequence;
|
2022-11-16 20:19:52 +01:00
|
|
|
displaySet.referencedSeriesInstanceUID = referencedSeries.SeriesInstanceUID;
|
2024-11-06 13:15:27 +01:00
|
|
|
const { displaySetService } = servicesManager.services;
|
|
|
|
|
const referencedDisplaySets = displaySetService.getDisplaySetsForSeries(
|
|
|
|
|
displaySet.referencedSeriesInstanceUID
|
|
|
|
|
);
|
2022-11-16 20:19:52 +01:00
|
|
|
|
2024-11-06 13:15:27 +01:00
|
|
|
const referencedDisplaySet = referencedDisplaySets[0];
|
|
|
|
|
|
|
|
|
|
if (!referencedDisplaySet) {
|
|
|
|
|
// subscribe to display sets added which means at some point it will be available
|
|
|
|
|
const { unsubscribe } = displaySetService.subscribe(
|
|
|
|
|
displaySetService.EVENTS.DISPLAY_SETS_ADDED,
|
|
|
|
|
({ displaySetsAdded }) => {
|
|
|
|
|
// here we can also do a little bit of search, since sometimes DICOM SEG
|
|
|
|
|
// does not contain the referenced display set uid , and we can just
|
|
|
|
|
// see which of the display sets added is more similar and assign it
|
|
|
|
|
// to the referencedDisplaySet
|
|
|
|
|
const addedDisplaySet = displaySetsAdded[0];
|
|
|
|
|
if (addedDisplaySet.SeriesInstanceUID === displaySet.referencedSeriesInstanceUID) {
|
|
|
|
|
displaySet.referencedDisplaySetInstanceUID = addedDisplaySet.displaySetInstanceUID;
|
|
|
|
|
unsubscribe();
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-16 20:19:52 +01:00
|
|
|
);
|
2024-11-06 13:15:27 +01:00
|
|
|
} else {
|
2023-09-01 22:19:39 +02:00
|
|
|
displaySet.referencedDisplaySetInstanceUID = referencedDisplaySet.displaySetInstanceUID;
|
2024-11-06 13:15:27 +01:00
|
|
|
}
|
2022-11-16 20:19:52 +01:00
|
|
|
|
|
|
|
|
displaySet.load = async ({ headers }) =>
|
|
|
|
|
await _load(displaySet, servicesManager, extensionManager, headers);
|
|
|
|
|
|
|
|
|
|
return [displaySet];
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-08 18:12:49 +02:00
|
|
|
function _load(
|
|
|
|
|
segDisplaySet,
|
|
|
|
|
servicesManager: AppTypes.ServicesManager,
|
|
|
|
|
extensionManager,
|
|
|
|
|
headers
|
|
|
|
|
) {
|
2022-11-16 20:19:52 +01:00
|
|
|
const { SOPInstanceUID } = segDisplaySet;
|
feat(RT): add dicom RT support via volume viewports (#3310)
* feat: initial RT support
* make the segmentation service work with representation data
* feat: make segmentation service work with representations
* fix rtss vis
* fix: rt hydration
* fix the rendering of rt names
* fix imports
* refactor: Modify status and click handling for hydration of RTStructures
Modify status and click handling for hydration of RTStructures by renaming `onPillClick` to `onStatusClick` in `OHIFCornerstoneRTViewport.tsx` and `_getStatusComponent.tsx` files. Also, update initial segmentation configurations in `PanelSegmentation.tsx` and simplify configuration changes and values for segmentation service in `SegmentationService.ts`. Finally, remove console debug in `CornerstoneViewportService.ts`.
* wip for highlighting contours
* refactor rt displayset code
* review code update
* update cornerstone dependencies
* refactor: Update license year, version number, and minor code cleanup
This commit updates the license year in several files, updates the version number in package.json, and contains minor code cleanup in two files.
* add bulkdataURI retrieve for RT
* fix package version
* apply review comments
* apply review comments
* apply review comments
* feat(panels): refactor and streamline segmentation configuration and inputs
Rewrote state hooks and streamlined the configuration input for `PanelSegmentation` to be more verbose and reusable. Included several new input types, including the `InputRange` component which now shows a fixed floating value based on the step provided. The `SegmentationConfig` component now works with dynamic values controlled by `initialConfig`. These changes should improve function usability and make the code more maintainable going forward.
* fix various bugs
* fix contour delete by upgrade cs3d version
* feat(viewport, inputNumber, segmentationConfig, orthanc): Implement minimum and maximum values for input number components, and useBulkDataURI for Orthanc configuration. Compare measurement view planes with absolute viewport view planes in Cornerstone viewport.
* update yarn lock
2023-04-26 18:21:08 +02:00
|
|
|
const { segmentationService } = servicesManager.services;
|
|
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
if (
|
|
|
|
|
(segDisplaySet.loading || segDisplaySet.isLoaded) &&
|
feat(RT): add dicom RT support via volume viewports (#3310)
* feat: initial RT support
* make the segmentation service work with representation data
* feat: make segmentation service work with representations
* fix rtss vis
* fix: rt hydration
* fix the rendering of rt names
* fix imports
* refactor: Modify status and click handling for hydration of RTStructures
Modify status and click handling for hydration of RTStructures by renaming `onPillClick` to `onStatusClick` in `OHIFCornerstoneRTViewport.tsx` and `_getStatusComponent.tsx` files. Also, update initial segmentation configurations in `PanelSegmentation.tsx` and simplify configuration changes and values for segmentation service in `SegmentationService.ts`. Finally, remove console debug in `CornerstoneViewportService.ts`.
* wip for highlighting contours
* refactor rt displayset code
* review code update
* update cornerstone dependencies
* refactor: Update license year, version number, and minor code cleanup
This commit updates the license year in several files, updates the version number in package.json, and contains minor code cleanup in two files.
* add bulkdataURI retrieve for RT
* fix package version
* apply review comments
* apply review comments
* apply review comments
* feat(panels): refactor and streamline segmentation configuration and inputs
Rewrote state hooks and streamlined the configuration input for `PanelSegmentation` to be more verbose and reusable. Included several new input types, including the `InputRange` component which now shows a fixed floating value based on the step provided. The `SegmentationConfig` component now works with dynamic values controlled by `initialConfig`. These changes should improve function usability and make the code more maintainable going forward.
* fix various bugs
* fix contour delete by upgrade cs3d version
* feat(viewport, inputNumber, segmentationConfig, orthanc): Implement minimum and maximum values for input number components, and useBulkDataURI for Orthanc configuration. Compare measurement view planes with absolute viewport view planes in Cornerstone viewport.
* update yarn lock
2023-04-26 18:21:08 +02:00
|
|
|
loadPromises[SOPInstanceUID] &&
|
2024-11-06 13:15:27 +01:00
|
|
|
_segmentationExists(segDisplaySet)
|
2022-11-16 20:19:52 +01:00
|
|
|
) {
|
|
|
|
|
return loadPromises[SOPInstanceUID];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
segDisplaySet.loading = true;
|
|
|
|
|
|
|
|
|
|
// We don't want to fire multiple loads, so we'll wait for the first to finish
|
|
|
|
|
// and also return the same promise to any other callers.
|
|
|
|
|
loadPromises[SOPInstanceUID] = new Promise(async (resolve, reject) => {
|
2023-09-01 22:19:39 +02:00
|
|
|
if (!segDisplaySet.segments || Object.keys(segDisplaySet.segments).length === 0) {
|
2024-10-30 00:14:34 +01:00
|
|
|
try {
|
|
|
|
|
await _loadSegments({
|
|
|
|
|
extensionManager,
|
|
|
|
|
servicesManager,
|
|
|
|
|
segDisplaySet,
|
|
|
|
|
headers,
|
|
|
|
|
});
|
|
|
|
|
} catch (e) {
|
|
|
|
|
segDisplaySet.loading = false;
|
|
|
|
|
return reject(e);
|
|
|
|
|
}
|
2022-11-16 20:19:52 +01:00
|
|
|
}
|
|
|
|
|
|
feat(RT): add dicom RT support via volume viewports (#3310)
* feat: initial RT support
* make the segmentation service work with representation data
* feat: make segmentation service work with representations
* fix rtss vis
* fix: rt hydration
* fix the rendering of rt names
* fix imports
* refactor: Modify status and click handling for hydration of RTStructures
Modify status and click handling for hydration of RTStructures by renaming `onPillClick` to `onStatusClick` in `OHIFCornerstoneRTViewport.tsx` and `_getStatusComponent.tsx` files. Also, update initial segmentation configurations in `PanelSegmentation.tsx` and simplify configuration changes and values for segmentation service in `SegmentationService.ts`. Finally, remove console debug in `CornerstoneViewportService.ts`.
* wip for highlighting contours
* refactor rt displayset code
* review code update
* update cornerstone dependencies
* refactor: Update license year, version number, and minor code cleanup
This commit updates the license year in several files, updates the version number in package.json, and contains minor code cleanup in two files.
* add bulkdataURI retrieve for RT
* fix package version
* apply review comments
* apply review comments
* apply review comments
* feat(panels): refactor and streamline segmentation configuration and inputs
Rewrote state hooks and streamlined the configuration input for `PanelSegmentation` to be more verbose and reusable. Included several new input types, including the `InputRange` component which now shows a fixed floating value based on the step provided. The `SegmentationConfig` component now works with dynamic values controlled by `initialConfig`. These changes should improve function usability and make the code more maintainable going forward.
* fix various bugs
* fix contour delete by upgrade cs3d version
* feat(viewport, inputNumber, segmentationConfig, orthanc): Implement minimum and maximum values for input number components, and useBulkDataURI for Orthanc configuration. Compare measurement view planes with absolute viewport view planes in Cornerstone viewport.
* update yarn lock
2023-04-26 18:21:08 +02:00
|
|
|
segmentationService
|
2024-11-06 13:15:27 +01:00
|
|
|
.createSegmentationForSEGDisplaySet(segDisplaySet)
|
2022-11-16 20:19:52 +01:00
|
|
|
.then(() => {
|
|
|
|
|
segDisplaySet.loading = false;
|
|
|
|
|
resolve();
|
|
|
|
|
})
|
|
|
|
|
.catch(error => {
|
|
|
|
|
segDisplaySet.loading = false;
|
|
|
|
|
reject(error);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return loadPromises[SOPInstanceUID];
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-08 18:12:49 +02:00
|
|
|
async function _loadSegments({
|
|
|
|
|
extensionManager,
|
|
|
|
|
servicesManager,
|
|
|
|
|
segDisplaySet,
|
|
|
|
|
headers,
|
|
|
|
|
}: withAppTypes) {
|
2022-11-16 20:19:52 +01:00
|
|
|
const utilityModule = extensionManager.getModuleEntry(
|
|
|
|
|
'@ohif/extension-cornerstone.utilityModule.common'
|
|
|
|
|
);
|
|
|
|
|
|
2023-12-13 21:03:09 +01:00
|
|
|
const { segmentationService, uiNotificationService } = servicesManager.services;
|
2023-08-08 20:39:31 +02:00
|
|
|
|
2022-11-16 20:19:52 +01:00
|
|
|
const { dicomLoaderService } = utilityModule.exports;
|
2023-09-01 22:19:39 +02:00
|
|
|
const arrayBuffer = await dicomLoaderService.findDicomDataPromise(segDisplaySet, null, headers);
|
2022-11-16 20:19:52 +01:00
|
|
|
|
2024-11-06 13:15:27 +01:00
|
|
|
const referencedDisplaySet = servicesManager.services.displaySetService.getDisplaySetByUID(
|
|
|
|
|
segDisplaySet.referencedDisplaySetInstanceUID
|
|
|
|
|
);
|
2022-11-16 20:19:52 +01:00
|
|
|
|
2024-11-06 13:15:27 +01:00
|
|
|
if (!referencedDisplaySet) {
|
|
|
|
|
throw new Error('referencedDisplaySet is missing for SEG');
|
2022-11-16 20:19:52 +01:00
|
|
|
}
|
|
|
|
|
|
2024-11-06 13:15:27 +01:00
|
|
|
const { instances: images } = referencedDisplaySet;
|
|
|
|
|
const imageIds = images.map(({ imageId }) => imageId);
|
2022-11-16 20:19:52 +01:00
|
|
|
|
2023-08-08 20:39:31 +02:00
|
|
|
// 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;
|
2023-09-01 22:19:39 +02:00
|
|
|
segmentationService._broadcastEvent(segmentationService.EVENTS.SEGMENT_LOADING_COMPLETE, {
|
|
|
|
|
percentComplete,
|
|
|
|
|
});
|
2022-11-16 20:19:52 +01:00
|
|
|
});
|
|
|
|
|
|
2023-08-08 20:39:31 +02:00
|
|
|
const results = await adaptersSEG.Cornerstone3D.Segmentation.generateToolState(
|
|
|
|
|
imageIds,
|
|
|
|
|
arrayBuffer,
|
|
|
|
|
metaData,
|
|
|
|
|
{ skipOverlapping, tolerance, eventTarget, triggerEvent }
|
2022-11-16 20:19:52 +01:00
|
|
|
);
|
|
|
|
|
|
2023-12-13 21:03:09 +01:00
|
|
|
let usedRecommendedDisplayCIELabValue = true;
|
2023-08-08 20:39:31 +02:00
|
|
|
results.segMetadata.data.forEach((data, i) => {
|
|
|
|
|
if (i > 0) {
|
2023-12-13 21:03:09 +01:00
|
|
|
data.rgba = data.RecommendedDisplayCIELabValue;
|
|
|
|
|
|
|
|
|
|
if (data.rgba) {
|
|
|
|
|
data.rgba = dicomlabToRGB(data.rgba);
|
|
|
|
|
} else {
|
|
|
|
|
usedRecommendedDisplayCIELabValue = false;
|
|
|
|
|
data.rgba = CONSTANTS.COLOR_LUT[i % CONSTANTS.COLOR_LUT.length];
|
|
|
|
|
}
|
2023-08-08 20:39:31 +02:00
|
|
|
}
|
2022-11-16 20:19:52 +01:00
|
|
|
});
|
|
|
|
|
|
2024-01-09 16:15:56 +01:00
|
|
|
if (results.overlappingSegments) {
|
|
|
|
|
uiNotificationService.show({
|
|
|
|
|
title: 'Overlapping Segments',
|
|
|
|
|
message:
|
|
|
|
|
'Unsupported overlapping segments detected, segmentation rendering results may be incorrect.',
|
|
|
|
|
type: 'warning',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-13 21:03:09 +01:00
|
|
|
if (!usedRecommendedDisplayCIELabValue) {
|
|
|
|
|
// Display a notification about the non-utilization of RecommendedDisplayCIELabValue
|
|
|
|
|
uiNotificationService.show({
|
|
|
|
|
title: 'DICOM SEG import',
|
|
|
|
|
message:
|
|
|
|
|
'RecommendedDisplayCIELabValue not found for one or more segments. The default color was used instead.',
|
|
|
|
|
type: 'warning',
|
|
|
|
|
duration: 5000,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-08 20:39:31 +02:00
|
|
|
Object.assign(segDisplaySet, results);
|
|
|
|
|
}
|
2022-11-16 20:19:52 +01:00
|
|
|
|
2024-11-06 13:15:27 +01:00
|
|
|
function _segmentationExists(segDisplaySet) {
|
|
|
|
|
return cstSegmentation.state.getSegmentation(segDisplaySet.displaySetInstanceUID);
|
2022-11-16 20:19:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getSopClassHandlerModule({ servicesManager, extensionManager }) {
|
|
|
|
|
const getDisplaySetsFromSeries = instances => {
|
2023-09-01 22:19:39 +02:00
|
|
|
return _getDisplaySetsFromSeries(instances, servicesManager, extensionManager);
|
2022-11-16 20:19:52 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
{
|
|
|
|
|
name: 'dicom-seg',
|
|
|
|
|
sopClassUids,
|
|
|
|
|
getDisplaySetsFromSeries,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default getSopClassHandlerModule;
|