Skip to content

Commit

Permalink
fix(segmentation): upgrade cs3d to fix various segmentation bugs (#3885)
Browse files Browse the repository at this point in the history
  • Loading branch information
sedghi authored Jan 9, 2024
1 parent a8a0bdb commit b1efe40
Show file tree
Hide file tree
Showing 26 changed files with 241 additions and 171 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ function OHIFCornerstoneRTViewport(props) {
}, [servicesManager, viewportId, rtDisplaySet, rtIsLoading]);

useEffect(() => {
// I'm not sure what is this, since in RT we support Overlapping segmnets

Check failure on line 171 in extensions/cornerstone-dicom-rt/src/viewports/OHIFCornerstoneRTViewport.tsx

View workflow job for this annotation

GitHub Actions / Check for spelling errors

segmnets ==> segments
// via contours
const { unsubscribe } = segmentationService.subscribe(
segmentationService.EVENTS.SEGMENTATION_LOADING_COMPLETE,
evt => {
Expand Down
6 changes: 3 additions & 3 deletions extensions/cornerstone-dicom-seg/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.40.3",
"@cornerstonejs/tools": "^1.40.3",
"@kitware/vtk.js": "27.3.1",
"@cornerstonejs/adapters": "^1.43.7",
"@cornerstonejs/tools": "^1.43.7",
"@kitware/vtk.js": "29.3.0",
"react-color": "^2.19.3"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,15 @@ async function _loadSegments({ extensionManager, servicesManager, segDisplaySet,
}
});

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({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createReportAsync } from '@ohif/extension-default';
import React, { useEffect, useState, useCallback } from 'react';
import PropTypes from 'prop-types';
import { SegmentationGroupTable, LegacyButtonGroup, LegacyButton } from '@ohif/ui';
import { SegmentationGroupTable } from '@ohif/ui';

import callInputDialog from './callInputDialog';
import callColorPickerDialog from './colorPickerDialog';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const initialState = {
},
ThresholdBrush: {
brushSize: 15,
thresholdRange: [-500, 500],
thresholdRange: null,
},
activeTool: null,
};
Expand Down Expand Up @@ -88,6 +88,8 @@ function SegmentationToolbox({ servicesManager, extensionManager }) {

const setToolActive = useCallback(
toolName => {
initializeThresholdValue(toolName);

toolbarService.recordInteraction({
interactionType: 'tool',
commands: [
Expand Down Expand Up @@ -178,6 +180,24 @@ function SegmentationToolbox({ servicesManager, extensionManager }) {
[toolGroupService]
);

function initializeThresholdValue(toolName: any) {
if (state.ThresholdBrush.thresholdRange === null) {
// set the default threshold range from the tool configuration
const toolGroupIds = toolGroupService.getToolGroupIds();
const toolGroupId = toolGroupIds[0];
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
const toolConfig = toolGroup.getToolConfiguration(toolName);
const defaultThresholdRange = toolConfig?.strategySpecificConfiguration?.THRESHOLD?.threshold;
dispatch({
type: ACTIONS.SET_TOOL_CONFIG,
payload: {
tool: 'ThresholdBrush',
config: { thresholdRange: defaultThresholdRange },
},
});
}
}

const onBrushSizeChange = useCallback(
(valueAsStringOrNumber, toolCategory) => {
const value = Number(valueAsStringOrNumber);
Expand All @@ -200,8 +220,8 @@ function SegmentationToolbox({ servicesManager, extensionManager }) {
const handleRangeChange = useCallback(
newRange => {
if (
newRange[0] === state.ThresholdBrush.thresholdRange[0] &&
newRange[1] === state.ThresholdBrush.thresholdRange[1]
newRange[0] === state.ThresholdBrush.thresholdRange?.[0] &&
newRange[1] === state.ThresholdBrush.thresholdRange?.[1]
) {
return;
}
Expand All @@ -213,7 +233,7 @@ function SegmentationToolbox({ servicesManager, extensionManager }) {
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
toolGroup.setToolConfiguration(toolName, {
strategySpecificConfiguration: {
THRESHOLD_INSIDE_CIRCLE: {
THRESHOLD: {
threshold: newRange,
},
},
Expand Down Expand Up @@ -365,7 +385,7 @@ function SegmentationToolbox({ servicesManager, extensionManager }) {
<InputDoubleRange
values={state.ThresholdBrush.thresholdRange}
onChange={handleRangeChange}
minValue={-1000}
minValue={-1000} // Todo: these should be configurable
maxValue={1000}
step={1}
showLabel={true}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,6 @@ function OHIFCornerstoneSEGViewport(props) {
if (evt.segDisplaySet.displaySetInstanceUID === segDisplaySet.displaySetInstanceUID) {
setSegIsLoading(false);
}

if (evt.overlappingSegments) {
uiNotificationService.show({
title: 'Overlapping Segments',
message: 'Overlapping segments detected which is not currently supported',
type: 'warning',
});
}
}
);

Expand Down
6 changes: 3 additions & 3 deletions extensions/cornerstone-dicom-sr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.40.3",
"@cornerstonejs/core": "^1.40.3",
"@cornerstonejs/tools": "^1.40.3",
"@cornerstonejs/adapters": "^1.43.7",
"@cornerstonejs/core": "^1.43.7",
"@cornerstonejs/tools": "^1.43.7",
"classnames": "^2.3.2"
}
}
12 changes: 6 additions & 6 deletions extensions/cornerstone/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.2",
"@cornerstonejs/codec-openjph": "^2.4.2",
"@cornerstonejs/dicom-image-loader": "^1.40.3",
"@cornerstonejs/dicom-image-loader": "^1.43.7",
"@ohif/core": "3.8.0-beta.42",
"@ohif/ui": "3.8.0-beta.42",
"dcmjs": "^0.29.12",
Expand All @@ -52,11 +52,11 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.40.3",
"@cornerstonejs/core": "^1.40.3",
"@cornerstonejs/streaming-image-volume-loader": "^1.40.3",
"@cornerstonejs/tools": "^1.40.3",
"@kitware/vtk.js": "27.3.1",
"@cornerstonejs/adapters": "^1.43.7",
"@cornerstonejs/core": "^1.43.7",
"@cornerstonejs/streaming-image-volume-loader": "^1.43.7",
"@cornerstonejs/tools": "^1.43.7",
"@kitware/vtk.js": "29.3.01",
"html2canvas": "^1.4.1",
"lodash.debounce": "4.0.8",
"lodash.merge": "^4.6.2",
Expand Down
6 changes: 3 additions & 3 deletions extensions/cornerstone/src/init.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -253,10 +253,10 @@ export default async function init({

/**
* Runs error handler for failed requests.
* @param event
* @param event
*/
const imageLoadFailedHandler = ({ detail }) => {
const handler = errorHandler.getHTTPErrorHandler()
const handler = errorHandler.getHTTPErrorHandler();
handler(detail.error);
};

Expand Down Expand Up @@ -290,7 +290,7 @@ export default async function init({
});
eventTarget.addEventListener(EVENTS.IMAGE_LOAD_FAILED, imageLoadFailedHandler);
eventTarget.addEventListener(EVENTS.IMAGE_LOAD_ERROR, imageLoadFailedHandler);

function elementEnabledHandler(evt) {
const { element } = evt.detail;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import cloneDeep from 'lodash.clonedeep';

import { Types as OhifTypes, ServicesManager, PubSubService } from '@ohif/core';
import {
cache,
Expand All @@ -11,7 +9,6 @@ import {
volumeLoader,
} from '@cornerstonejs/core';
import {
CONSTANTS as cstConstants,
Enums as csToolsEnums,
segmentation as cstSegmentation,
Types as cstTypes,
Expand All @@ -23,7 +20,6 @@ import { easeInOutBell, reverseEaseInOutBell } from '../../utils/transitions';
import { Segment, Segmentation, SegmentationConfig } from './SegmentationServiceTypes';
import { mapROIContoursToRTStructData } from './RTSTRUCT/mapROIContoursToRTStructData';

const { COLOR_LUT } = cstConstants;
const LABELMAP = csToolsEnums.SegmentationRepresentations.Labelmap;
const CONTOUR = csToolsEnums.SegmentationRepresentations.Contour;

Expand Down Expand Up @@ -465,15 +461,6 @@ class SegmentationService extends PubSubService {
},
]);

// if first segmentation, we can use the default colorLUT, otherwise
// we need to generate a new one and use a new colorLUT
const colorLUTIndex = 0;
if (Object.keys(this.segmentations).length !== 0) {
const newColorLUT = this.generateNewColorLUT();
const colorLUTIndex = this.getNextColorLUTIndex();
cstSegmentation.config.color.addColorLUT(newColorLUT, colorLUTIndex);
}

this.segmentations[segmentationId] = {
...segmentation,
label: segmentation.label || '',
Expand All @@ -482,7 +469,6 @@ class SegmentationService extends PubSubService {
segmentCount: segmentation.segmentCount ?? 0,
isActive: false,
isVisible: true,
colorLUTIndex,
};

cachedSegmentation = this.segmentations[segmentationId];
Expand Down Expand Up @@ -1037,8 +1023,6 @@ class SegmentationService extends PubSubService {
segmentation.hydrated = true;
}

const { colorLUTIndex } = segmentation;

// Based on the segmentationId, set the colorLUTIndex.
const segmentationRepresentationUIDs = await cstSegmentation.addSegmentationRepresentations(
toolGroupId,
Expand All @@ -1057,12 +1041,6 @@ class SegmentationService extends PubSubService {
segmentationRepresentationUIDs[0]
);

cstSegmentation.config.color.setColorLUT(
toolGroupId,
segmentationRepresentationUIDs[0],
colorLUTIndex
);

// add the segmentation segments properly
for (const segment of segmentation.segments) {
if (segment === null || segment === undefined) {
Expand Down Expand Up @@ -1530,7 +1508,6 @@ class SegmentationService extends PubSubService {
segments: [],
isVisible: true,
isActive: false,
colorLUTIndex: 0,
};
}

Expand Down Expand Up @@ -2124,23 +2101,6 @@ class SegmentationService extends PubSubService {
return viewportInfo.getToolGroupId();
};

private getNextColorLUTIndex = (): number => {
let i = 0;
while (true) {
if (cstSegmentation.state.getColorLUT(i) === undefined) {
return i;
}

i++;
}
};

private generateNewColorLUT() {
const newColorLUT = cloneDeep(COLOR_LUT);

return newColorLUT;
}

/**
* Converts object of objects to array.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Types, Enums } from '@cornerstonejs/core';
import { Types as UITypes } from '@ohif/ui';
import { Types as CoreTypes } from '@ohif/core';
import { StackViewportData, VolumeViewportData } from '../../types/CornerstoneCacheService';
import getCornerstoneBlendMode from '../../utils/getCornerstoneBlendMode';
import getCornerstoneOrientation from '../../utils/getCornerstoneOrientation';
Expand All @@ -18,7 +18,7 @@ export type ViewportOptions = {
toolGroupId: string;
viewportId: string;
// Presentation ID to store/load presentation state from
presentationIds?: UITypes.PresentationIds;
presentationIds?: CoreTypes.PresentationIds;
orientation?: Enums.OrientationAxis;
background?: Types.Point3;
displayArea?: Types.DisplayArea;
Expand All @@ -36,7 +36,7 @@ export type PublicViewportOptions = {
id?: string;
viewportType?: string;
toolGroupId?: string;
presentationIds?: UITypes.PresentationIds;
presentationIds?: CoreTypes.PresentationIds;
viewportId?: string;
orientation?: Enums.OrientationAxis;
background?: Types.Point3;
Expand Down Expand Up @@ -71,7 +71,7 @@ export type DisplaySetOptions = {
voiInverted: boolean;
blendMode?: Enums.BlendModes;
slabThickness?: number;
colormap?: { name: string, opacity?: number };
colormap?: { name: string; opacity?: number };
displayPreset?: string;
};

Expand Down
4 changes: 2 additions & 2 deletions extensions/cornerstone/src/types/Presentation.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/** Store presentation data for either stack viewports or volume viewports */
import { Types } from '@cornerstonejs/core';
import { Types as UITypes } from '@ohif/ui';
import { Types as CoreTypes } from '@ohif/core';

/**
* Has information on the presentation of the viewport.
*/
export interface Presentation extends Types.StackViewportProperties {
presentationIds: UITypes.PresentationIds;
presentationIds: CoreTypes.PresentationIds;
viewportType: string;
initialImageIndex: number;
camera: Types.ICamera;
Expand Down
4 changes: 2 additions & 2 deletions extensions/measurement-tracking/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@cornerstonejs/core": "^1.40.3",
"@cornerstonejs/tools": "^1.40.3",
"@cornerstonejs/core": "^1.43.7",
"@cornerstonejs/tools": "^1.43.7",
"@ohif/core": "3.8.0-beta.42",
"@ohif/extension-cornerstone-dicom-sr": "3.8.0-beta.42",
"@ohif/ui": "3.8.0-beta.42",
Expand Down
Loading

0 comments on commit b1efe40

Please sign in to comment.