feat: Segmentations Settings UI - Phase 1 #1391 (#1392)

* Filter segs and fetch correct metadata.

* Initiate seg loading logic on series load into viewport. Need to write.

* Automatic consumption of SEG functional.

* Pull in master.

* Fix issues after pulling in master.

* Clean up old segmentation handlers.

* WIP

* WIP

* Poppulate viewport with metadata.

* Show hide/segmentation in react-vtkjs-viewport.

* feat: 🎸 View segmentations in vtkjs viewport

* Filter segs and fetch correct metadata.

* Initiate seg loading logic on series load into viewport. Need to write.

* Automatic consumption of SEG functional.

* Pull in master.

* Fix issues after pulling in master.

* Clean up old segmentation handlers.

* WIP

* WIP

* Poppulate viewport with metadata.

* Show hide/segmentation in react-vtkjs-viewport.

* feat: 🎸 View segmentations in vtkjs viewport

* Rebase on master.

* format format format

* add basic extension parts

* Updated yarn lock

* Fetch derived/referenced displaysets in sidepanel

* Add buttons, expose seriesDescription, write notes for Danny.

* Add growcut tool extention. -> Move to a seperate repo.

* Change some text fields.

* expose dialog provider

* hide draggable area

* No pointer events for now; need to revisit

* Don't filter seg from the outset for now

* fiddling about

* fix path to series data

* fix logic to determine next available labelmapindex

* Ability to swtich between labelmaps

* Return a promise so we can make sure our labelmap is loaded before pulling metadata

* Better UI to toggle labelmaps

* Fix accidental untoggle of active labelmap for ui

* Remove brush tool from cornerstone extension

* Add cstools in preInit for seg extension

* Add buttons for seg magic

* Hide the measurements panel for now

* Slightly better seg/scissor icons

* Add eraser

* ability to switch segments

* seg color / switcher

* Fix vtk labelmap cache.

* sidepanel should scroll if there's overflow

* Use a fancier range slider

* Slightly prettier buttons

* Push in progress

* A bit more reactive; handle no-meta

* Update to vtk.js 11.14.0 and react-vtkjs-viewport 0.6.0

* chore: kickstart preview

* Fix conflict issues

* Refactor panel

* Isolate increment functions

* Wip segment table

* Hide selector and add scroll to segmentation

* Increase width of segment description

* Hide not used items

* Add new select for segmentations

* Align ui

* Fix default segmentation

* Fix broken import test

* Get measurements panel back and add spacing to grouped buttons

* Hide brush and selector and refresh when switching segmentations

* Add pointer events back and fix broken tests for measurement table

* Update segment list when switching humbnails

* CR Update: Minor UI adjustments

* CR Update: Set active segment

* Move components to components folder

* Add new settings ui

* Integrate configuration

* Improve styles

* Float numbers

* Improve css

* Refresh settings menu if side panel changed

* Fix settings rendering logic and remove comments

* Extract components

* Remove not used tools

* Remove non used extension

* Use style variables and remove comments

* Remove non used dep from lock

* Remove tools

* Remove segmentation from toolbar

* Add todo and brushradius from config

* Fix packagejson growcut import

* Remove webpack config already defined in parent

* Update package json description

* Change component name to british english to us

* Improve prop types

* Rename cornerstone label map event

* Scope css

* Extract and add doc to helper

* Update jsdocs for getDerivedDatasets

* Add proptypes and cr updates

* Update tablistitem proptypes

* config is readonly, rollback destructuring

* Remove event for side panel

* Add jsdocs for util

* Extract getimageid to studymetada

* Use ohif log instead of console

* Remove specific style from side panel

* Fix default props for brush radius

* Descructure configuration props from settings component to avoid invalid props

* Update proptypes to be required (settings)

* Update readme

* Remove commandsmodule

* Get configuration module inside the component

* Set selected segment

* Rename extension and use modality to filter

* Fix for failing tests (#1423)

* hello world

* Finish rebase for Igor.

* Re-fix cornerstoneTools version that got messed up in merge.

* Fix reactivity of isDisabled, write implementation for the SEG panel.

* Nuke yarn.lock to stack CST to 4.12.0

* Remove debugger statements.

* fix: bump cornerstone-tools version to address toFixed issue

* test: force tests for MISTER^MR to navigate to study directly

* test: remove eraser tool test

* test: count is off by one

* test: don't save SR state for the time being

* test: disable more tests

Co-authored-by: James A. Petts <jamesapetts@gmail.com>
Co-authored-by: dannyrb <danny.ri.brown@gmail.com>
Co-authored-by: igoroctaviano] <igoroctaviano@users.noreply.github.com>
Co-authored-by: Mirna Silva <mirna.silva@radicalimaging.com>
This commit is contained in:
authored and GitHub committed 2020-03-13 15:45:26 -04:00
1 parent d426b78967
commit e8842cf8ae
78 files changed
+3071 -1962

No files matched your search

+1 -1
View File
@@ -34,7 +34,7 @@
"@ohif/ui": "^0.50.0",
"cornerstone-core": "^2.2.8",
"cornerstone-math": "^0.1.8",
"cornerstone-tools": "4.12.0",
"cornerstone-tools": "4.12.5",
"cornerstone-wado-image-loader": "^3.0.0",
"dcmjs": "^0.10.1",
"dicom-parser": "^1.8.3",
@@ -4,19 +4,9 @@ import ConnectedCornerstoneViewport from './ConnectedCornerstoneViewport';
import OHIF from '@ohif/core';
import PropTypes from 'prop-types';
import cornerstone from 'cornerstone-core';
import handleSegmentationStorage from './handleSegmentationStorage.js';
const { StackManager } = OHIF.utils;
const SOP_CLASSES = {
SEGMENTATION_STORAGE: '1.2.840.10008.5.1.4.1.1.66.4',
};
const specialCaseHandlers = {};
specialCaseHandlers[
SOP_CLASSES.SEGMENTATION_STORAGE
] = handleSegmentationStorage;
class OHIFCornerstoneViewport extends Component {
state = {
viewportData: null,
@@ -124,42 +114,24 @@ class OHIFCornerstoneViewport extends Component {
studies,
StudyInstanceUID,
displaySetInstanceUID,
SOPClassUID,
SOPInstanceUID,
frameIndex
) => {
let viewportData;
switch (SOPClassUID) {
case SOP_CLASSES.SEGMENTATION_STORAGE:
const specialCaseHandler =
specialCaseHandlers[SOP_CLASSES.SEGMENTATION_STORAGE];
const stack = OHIFCornerstoneViewport.getCornerstoneStack(
studies,
StudyInstanceUID,
displaySetInstanceUID,
SOPInstanceUID,
frameIndex
);
viewportData = await specialCaseHandler(
studies,
StudyInstanceUID,
displaySetInstanceUID,
SOPInstanceUID,
frameIndex
);
break;
default:
const stack = OHIFCornerstoneViewport.getCornerstoneStack(
studies,
StudyInstanceUID,
displaySetInstanceUID,
SOPInstanceUID,
frameIndex
);
viewportData = {
StudyInstanceUID,
displaySetInstanceUID,
stack,
};
break;
}
viewportData = {
StudyInstanceUID,
displaySetInstanceUID,
stack,
};
return viewportData;
};
@@ -184,13 +156,10 @@ class OHIFCornerstoneViewport extends Component {
);
}
const SOPClassUID = sopClassUIDs && sopClassUIDs[0];
this.getViewportData(
studies,
StudyInstanceUID,
displaySetInstanceUID,
SOPClassUID,
SOPInstanceUID,
frameIndex
).then(viewportData => {
@@ -205,7 +174,7 @@ class OHIFCornerstoneViewport extends Component {
}
componentDidUpdate(prevProps) {
const { studies, displaySet } = this.props.viewportData;
const { displaySet } = this.props.viewportData;
const prevDisplaySet = prevProps.viewportData.displaySet;
if (
@@ -1,128 +0,0 @@
import * as dcmjs from 'dcmjs';
import OHIF from '@ohif/core';
import cornerstone from 'cornerstone-core';
import cornerstoneTools from 'cornerstone-tools';
const { StackManager, DicomLoaderService } = OHIF.utils;
function getDisplaySet(studies, StudyInstanceUID, displaySetInstanceUID) {
const study = studies.find(
study => study.StudyInstanceUID === StudyInstanceUID
);
const displaySet = study.displaySets.find(set => {
return set.displaySetInstanceUID === displaySetInstanceUID;
});
return displaySet;
}
function getDisplaySetsBySeries(studies, StudyInstanceUID, SeriesInstanceUID) {
const study = studies.find(
study => study.StudyInstanceUID === StudyInstanceUID
);
return study.displaySets.filter(set => {
return set.SeriesInstanceUID === SeriesInstanceUID;
});
}
function parseSeg(arrayBuffer, imageIds) {
return dcmjs.adapters.Cornerstone.Segmentation.generateToolState(
imageIds,
arrayBuffer,
cornerstone.metaData
);
}
function addSegMetadataToCornerstoneToolState(
segMetadata,
toolState,
displaySetInstanceUID
) {
cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState(
toolState
);
const brushModule = cornerstoneTools.store.modules.brush;
for (let i = 0; i < segMetadata.length; i++) {
brushModule.setters.metadata(displaySetInstanceUID, i, segMetadata[i]);
}
}
async function handleSegmentationStorage(
studies,
StudyInstanceUID,
displaySetInstanceUID
) {
const study = studies.find(
study => study.StudyInstanceUID === StudyInstanceUID
);
const displaySet = getDisplaySet(
studies,
StudyInstanceUID,
displaySetInstanceUID
);
const arrayBuffer = await DicomLoaderService.findDicomDataPromise(
displaySet,
studies
);
const dicomData = dcmjs.data.DicomMessage.readFile(arrayBuffer);
const dataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(
dicomData.dict
);
dataset._meta = dcmjs.data.DicomMetaDictionary.namifyDataset(dicomData.meta);
const SeriesInstanceUID = dataset.ReferencedSeriesSequence.SeriesInstanceUID;
const displaySets = getDisplaySetsBySeries(
studies,
StudyInstanceUID,
SeriesInstanceUID
);
if (displaySets.length > 1) {
console.warn(
'More than one display set with the same SeriesInstanceUID. This is not supported yet...'
);
}
const referenceDisplaySet = displaySets[0];
const imageIds = referenceDisplaySet.images.map(image => image.getImageId());
const results = parseSeg(arrayBuffer, imageIds);
if (!results) {
throw new Error('Fractional segmentations are not supported');
}
const { labelmapBuffer, segMetadata, segmentsOnFrame } = results;
const { setters } = cornerstoneTools.getModule('segmentation');
setters.labelmap3DByFirstImageId(
imageIds[0],
labelmapBuffer,
0, // TODO -> Can define a color LUT based on colors in the SEG later.
segMetadata,
imageIds.length,
segmentsOnFrame
);
const cachedStack = StackManager.findOrCreateStack(
study,
referenceDisplaySet
);
const stack = Object.assign({}, cachedStack);
stack.currentImageIdIndex = 0;
return {
StudyInstanceUID,
displaySetInstanceUID,
stack,
};
}
export default handleSegmentationStorage;
-1
View File
@@ -66,7 +66,6 @@ export default function init({ servicesManager, configuration }) {
csTools.DragProbeTool,
csTools.RectangleRoiTool,
],
segmentation: [csTools.BrushTool],
other: [
csTools.PanTool,
csTools.ZoomTool,