fix: segmentation not loading (#1566)

* Fix bug

* Refactor the state of the component RTPanel
This commit is contained in:
Igor Octaviano 2020-04-01 00:54:02 -03:00 committed by GitHub
parent 333677c40e
commit 4a7ce1c093
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 90 additions and 92 deletions

View File

@ -14,7 +14,7 @@ const OHIFDicomSegSopClassHandler = {
id: 'OHIFDicomSegSopClassHandler', id: 'OHIFDicomSegSopClassHandler',
type: MODULE_TYPES.SOP_CLASS_HANDLER, type: MODULE_TYPES.SOP_CLASS_HANDLER,
sopClassUIDs, sopClassUIDs,
getDisplaySetFromSeries: function( getDisplaySetFromSeries: function (
series, series,
study, study,
dicomWebClient, dicomWebClient,
@ -53,7 +53,7 @@ const OHIFDicomSegSopClassHandler = {
SeriesDescription, SeriesDescription,
}; };
segDisplaySet.load = function(referencedDisplaySet, studies) { segDisplaySet.load = function (referencedDisplaySet, studies) {
return loadSegmentation( return loadSegmentation(
segDisplaySet, segDisplaySet,
referencedDisplaySet, referencedDisplaySet,

View File

@ -39,50 +39,26 @@ const SegmentationPanel = ({ studies, viewports, activeIndex, isOpen }) => {
* TODO: wrap get/set interactions with the cornerstoneTools * TODO: wrap get/set interactions with the cornerstoneTools
* store with context to make these kind of things less blurry. * store with context to make these kind of things less blurry.
*/ */
const segmentationModule = cornerstoneTools.getModule('segmentation'); const { configuration } = cornerstoneTools.getModule('segmentation');
const { configuration } = segmentationModule;
const DEFAULT_BRUSH_RADIUS = configuration.radius || 10; const DEFAULT_BRUSH_RADIUS = configuration.radius || 10;
const [state, setState] = useState({
const [brushRadius, setBrushRadius] = useState(DEFAULT_BRUSH_RADIUS); brushRadius: DEFAULT_BRUSH_RADIUS,
brushColor: 'rgba(221, 85, 85, 1)', /* TODO: We shouldn't hardcode this color, in the future the SEG may set the colorLUT to whatever it wants. */
/* TODO: We shouldn't hardcode this color, in the future the SEG may set the colorLUT to whatever it wants. */ selectedSegment: null,
const [brushColor, setBrushColor] = useState('rgba(221, 85, 85, 1)'); selectedSegmentation: null,
const [selectedSegment, setSelectedSegment] = useState(); showSegSettings: false,
const [showSegSettings, setShowSegSettings] = useState(false); brushStackState: null,
const [selectedSegmentation, setSelectedSegmentation] = useState(); labelmapList: [],
segmentList: []
const viewport = viewports[activeIndex]; });
const {
StudyInstanceUID,
SeriesInstanceUID,
displaySetInstanceUID,
} = viewport;
const studyMetadata = studyMetadataManager.get(StudyInstanceUID);
const firstImageId = studyMetadata.getFirstImageId(displaySetInstanceUID);
/* CornerstoneTools */
const [brushStackState, setBrushStackState] = useState(
segmentationModule.state.series[firstImageId]
);
useEffect(() => { useEffect(() => {
setShowSegSettings(showSegSettings && !isOpen);
}, [isOpen]);
useEffect(() => {
setBrushStackState(segmentationModule.state.series[firstImageId]);
}, [studies, viewports, activeIndex, firstImageId]);
useEffect(() => {
if (brushStackState) {
setSelectedSegmentation(brushStackState.activeLabelmapIndex);
}
const labelmapModifiedHandler = event => { const labelmapModifiedHandler = event => {
log.warn('labelmap modified', event); log.warn('Segmentation Panel: labelmap modified', event);
setBrushStackState(segmentationModule.state.series[firstImageId]); const module = cornerstoneTools.getModule('segmentation');
const activeViewport = viewports[activeIndex];
const firstImageId = studyMetadata.getFirstImageId(activeViewport.displaySetInstanceUID);
updateState('brushStackState', module.state.series[firstImageId]);
}; };
/* /*
@ -107,27 +83,43 @@ const SegmentationPanel = ({ studies, viewports, activeIndex, isOpen }) => {
}; };
}); });
if (!brushStackState) { useEffect(() => {
return null; const module = cornerstoneTools.getModule('segmentation');
const activeViewport = viewports[activeIndex];
const studyMetadata = studyMetadataManager.get(activeViewport.StudyInstanceUID);
const firstImageId = studyMetadata.getFirstImageId(activeViewport.displaySetInstanceUID);
const brushStackState = module.state.series[firstImageId];
if (brushStackState) {
const labelmap3D = brushStackState.labelmaps3D[brushStackState.activeLabelmapIndex];
const labelmapList = getLabelmapList(brushStackState, firstImageId, activeViewport);
const segmentList = getSegmentList(labelmap3D, firstImageId);
setState(state => ({
...state,
brushStackState,
selectedSegmentation: brushStackState.activeLabelmapIndex,
labelmapList,
segmentList
}));
} else {
setState(state => ({
...state,
labelmapList: [],
segmentList: [],
}));
} }
}, [studies, viewports, activeIndex]);
const labelmap3D = /* Handle open/closed panel behaviour */
brushStackState.labelmaps3D[brushStackState.activeLabelmapIndex]; useEffect(() => {
updateState('showSegSettings', state.showSegSettings && !isOpen);
}, [isOpen]);
/* const getLabelmapList = (brushStackState, firstImageId, activeViewport) => {
* 2. UseEffect to update state? or to a least trigger a re-render
* 4. Toggle visibility of labelmap?
* 5. Toggle visibility of seg?
*
* If the port is cornerstone, just need to call a re-render.
* If the port is vtkjs, its a bit more tricky as we now need to create a new
*/
const getLabelmapList = () => {
/* Get list of SEG labelmaps specific to active viewport (reference series) */ /* Get list of SEG labelmaps specific to active viewport (reference series) */
const referencedSegDisplaysets = _getReferencedSegDisplaysets( const referencedSegDisplaysets = _getReferencedSegDisplaysets(
StudyInstanceUID, activeViewport.StudyInstanceUID,
SeriesInstanceUID activeViewport.SeriesInstanceUID
); );
return referencedSegDisplaysets.map((displaySet, index) => { return referencedSegDisplaysets.map((displaySet, index) => {
@ -148,23 +140,19 @@ const SegmentationPanel = ({ studies, viewports, activeIndex, isOpen }) => {
description: displayDate, description: displayDate,
onClick: async () => { onClick: async () => {
const activatedLabelmapIndex = await _setActiveLabelmap( const activatedLabelmapIndex = await _setActiveLabelmap(
viewport, activeViewport,
studies, studies,
displaySet, displaySet,
firstImageId, firstImageId,
brushStackState.activeLabelmapIndex brushStackState.activeLabelmapIndex
); );
setSelectedSegmentation(activatedLabelmapIndex); updateState('selectedSegmentation', activatedLabelmapIndex);
}, },
}; };
}); });
}; };
const labelmapList = getLabelmapList(); const getSegmentList = (labelmap3D, firstImageId) => {
const segmentList = [];
if (labelmap3D) {
/* /*
* Newly created segments have no `meta` * Newly created segments have no `meta`
* So we instead build a list of all segment indexes in use * So we instead build a list of all segment indexes in use
@ -186,10 +174,12 @@ const SegmentationPanel = ({ studies, viewports, activeIndex, isOpen }) => {
}, []) }, [])
.sort((a, b) => a - b); .sort((a, b) => a - b);
const module = cornerstoneTools.getModule('segmentation');
const colorLutTable = const colorLutTable =
segmentationModule.state.colorLutTables[labelmap3D.colorLUTIndex]; module.state.colorLutTables[labelmap3D.colorLUTIndex];
const hasLabelmapMeta = labelmap3D.metadata && labelmap3D.metadata.data; const hasLabelmapMeta = labelmap3D.metadata && labelmap3D.metadata.data;
const segmentList = [];
for (let i = 0; i < uniqueSegmentIndexes.length; i++) { for (let i = 0; i < uniqueSegmentIndexes.length; i++) {
const segmentIndex = uniqueSegmentIndexes[i]; const segmentIndex = uniqueSegmentIndexes[i];
@ -207,14 +197,14 @@ const SegmentationPanel = ({ studies, viewports, activeIndex, isOpen }) => {
} }
} }
const sameSegment = selectedSegment === segmentNumber; const sameSegment = state.selectedSegment === segmentNumber;
const setCurrentSelectedSegment = () => { const setCurrentSelectedSegment = () => {
_setActiveSegment( _setActiveSegment(
firstImageId, firstImageId,
segmentNumber, segmentNumber,
labelmap3D.activeSegmentIndex labelmap3D.activeSegmentIndex
); );
setSelectedSegment(sameSegment ? null : segmentNumber); updateState('selectedSegment', sameSegment ? null : segmentNumber);
}; };
segmentList.push( segmentList.push(
@ -229,20 +219,27 @@ const SegmentationPanel = ({ studies, viewports, activeIndex, isOpen }) => {
); );
} }
return segmentList;
/* /*
* Let's iterate over segmentIndexes ^ above * Let's iterate over segmentIndexes ^ above
* If meta has a match, use it to show info * If meta has a match, use it to show info
* If now, add "no-meta" class * If now, add "no-meta" class
* Show default name * Show default name
*/ */
} };
const updateState = (field, value) => {
setState(state => ({ ...state, [field]: value }));
};
const updateBrushSize = evt => { const updateBrushSize = evt => {
const updatedRadius = Number(evt.target.value); const updatedRadius = Number(evt.target.value);
if (updatedRadius !== brushRadius) { if (updatedRadius !== brushRadius) {
setBrushRadius(updatedRadius); updateState('brushRadius', updatedRadius);
segmentationModule.setters.radius(updatedRadius); const module = cornerstoneTools.getModule('segmentation');
module.setters.radius(updatedRadius);
} }
}; };
@ -251,29 +248,30 @@ const SegmentationPanel = ({ studies, viewports, activeIndex, isOpen }) => {
if (labelmap3D.activeSegmentIndex > 1) { if (labelmap3D.activeSegmentIndex > 1) {
labelmap3D.activeSegmentIndex--; labelmap3D.activeSegmentIndex--;
} }
setSelectedSegment(labelmap3D.activeSegmentIndex); updateState('selectedSegment', labelmap3D.activeSegmentIndex);
updateActiveSegmentColor(); updateActiveSegmentColor();
}; };
const incrementSegment = event => { const incrementSegment = event => {
event.preventDefault(); event.preventDefault();
labelmap3D.activeSegmentIndex++; labelmap3D.activeSegmentIndex++;
setSelectedSegment(labelmap3D.activeSegmentIndex); updateState('selectedSegment', labelmap3D.activeSegmentIndex);
updateActiveSegmentColor(); updateActiveSegmentColor();
}; };
const updateActiveSegmentColor = () => { const updateActiveSegmentColor = () => {
const color = getActiveSegmentColor(); const color = getActiveSegmentColor();
setBrushColor(color); updateState('brushColor', color);
}; };
const getActiveSegmentColor = () => { const getActiveSegmentColor = () => {
if (!brushStackState) { if (!state.brushStackState) {
return 'rgba(255, 255, 255, 1)'; return 'rgba(255, 255, 255, 1)';
} }
const module = cornerstoneTools.getModule('segmentation');
const colorLutTable = const colorLutTable =
segmentationModule.state.colorLutTables[labelmap3D.colorLUTIndex]; module.state.colorLutTables[labelmap3D.colorLUTIndex];
const color = colorLutTable[labelmap3D.activeSegmentIndex]; const color = colorLutTable[labelmap3D.activeSegmentIndex];
return `rgba(${color.join(',')})`; return `rgba(${color.join(',')})`;
@ -293,11 +291,11 @@ const SegmentationPanel = ({ studies, viewports, activeIndex, isOpen }) => {
refreshViewport(); refreshViewport();
}; };
if (showSegSettings) { if (state.showSegSettings) {
return ( return (
<SegmentationSettings <SegmentationSettings
configuration={configuration} configuration={configuration}
onBack={() => setShowSegSettings(false)} onBack={() => updateState('showSegSettings', false)}
onChange={updateConfiguration} onChange={updateConfiguration}
/> />
); );
@ -309,13 +307,13 @@ const SegmentationPanel = ({ studies, viewports, activeIndex, isOpen }) => {
name="cog" name="cog"
width="25px" width="25px"
height="25px" height="25px"
onClick={() => setShowSegSettings(true)} onClick={() => updateState('showSegSettings', true)}
/> />
{false && ( {false && (
<form className="selector-form"> <form className="selector-form">
<BrushColorSelector <BrushColorSelector
defaultColor={brushColor} defaultColor={brushColor}
index={labelmap3D.activeSegmentIndex} index={state.selectedSegment}
onNext={incrementSegment} onNext={incrementSegment}
onPrev={decrementSegment} onPrev={decrementSegment}
/> />
@ -331,17 +329,17 @@ const SegmentationPanel = ({ studies, viewports, activeIndex, isOpen }) => {
<div className="segmentations"> <div className="segmentations">
<SegmentationSelect <SegmentationSelect
value={ value={
labelmapList.find(i => i.value === selectedSegmentation) || null state.labelmapList.find(i => i.value === state.selectedSegmentation) || null
} }
formatOptionLabel={SegmentationItem} formatOptionLabel={SegmentationItem}
options={labelmapList} options={state.labelmapList}
/> />
</div> </div>
<ScrollableArea> <ScrollableArea>
<TableList <TableList
customHeader={<SegmentsHeader count={segmentList.length} />} customHeader={<SegmentsHeader count={state.segmentList.length} />}
> >
{segmentList} {state.segmentList}
</TableList> </TableList>
</ScrollableArea> </ScrollableArea>
</div> </div>
@ -420,7 +418,7 @@ const _setActiveLabelmap = async (
) => { ) => {
if (displaySet.labelmapIndex === activeLabelmapIndex) { if (displaySet.labelmapIndex === activeLabelmapIndex) {
log.warn(`${activeLabelmapIndex} is already the active labelmap`); log.warn(`${activeLabelmapIndex} is already the active labelmap`);
return; return displaySet.labelmapIndex;
} }
if (!displaySet.isLoaded) { if (!displaySet.isLoaded) {
@ -431,7 +429,6 @@ const _setActiveLabelmap = async (
const { state } = cornerstoneTools.getModule('segmentation'); const { state } = cornerstoneTools.getModule('segmentation');
const brushStackState = state.series[firstImageId]; const brushStackState = state.series[firstImageId];
brushStackState.activeLabelmapIndex = displaySet.labelmapIndex; brushStackState.activeLabelmapIndex = displaySet.labelmapIndex;
refreshViewport(); refreshViewport();

View File

@ -78,7 +78,7 @@ export class StudyMetadata extends Metadata {
Object.defineProperty(this, 'studyInstanceUID', { Object.defineProperty(this, 'studyInstanceUID', {
configurable: false, configurable: false,
enumerable: false, enumerable: false,
get: function() { get: function () {
return this.getStudyInstanceUID(); return this.getStudyInstanceUID();
}, },
}); });
@ -208,20 +208,21 @@ export class StudyMetadata extends Metadata {
/** /**
* Returns a list of derived datasets in the study, filtered by the given filter. * Returns a list of derived datasets in the study, filtered by the given filter.
* @param {object} filter An object containing search filters * @param {object} filter An object containing search filters
* @param {object} filter.modality * @param {object} filter.Modality
* @param {object} filter.referencedSeriesInstanceUID * @param {object} filter.referencedSeriesInstanceUID
* @param {object} filter.referencedFrameOfReferenceUID * @param {object} filter.referencedFrameOfReferenceUID
* @return {Array} filtered derived display sets * @return {Array} filtered derived display sets
*/ */
getDerivedDatasets(filter) { getDerivedDatasets(filter) {
const { const {
modality, Modality,
referencedSeriesInstanceUID, referencedSeriesInstanceUID,
referencedFrameOfReferenceUID, referencedFrameOfReferenceUID,
} = filter; } = filter;
let filteredDerivedDisplaySets = this._derivedDisplaySets; let filteredDerivedDisplaySets = this._derivedDisplaySets;
if (modality) { if (Modality) {
filteredDerivedDisplaySets = filteredDerivedDisplaySets.filter( filteredDerivedDisplaySets = filteredDerivedDisplaySets.filter(
displaySet => displaySet.Modality === Modality displaySet => displaySet.Modality === Modality
); );

View File

@ -11,7 +11,7 @@ import EmptyViewport from './EmptyViewport.js';
const { loadAndCacheDerivedDisplaySets } = utils; const { loadAndCacheDerivedDisplaySets } = utils;
const ViewportGrid = function(props) { const ViewportGrid = function (props) {
const { const {
activeViewportIndex, activeViewportIndex,
availablePlugins, availablePlugins,
@ -37,7 +37,7 @@ const ViewportGrid = function(props) {
viewportData.forEach(displaySet => { viewportData.forEach(displaySet => {
loadAndCacheDerivedDisplaySets(displaySet, studies); loadAndCacheDerivedDisplaySets(displaySet, studies);
}); });
}, [viewportData]); }, [studies, viewportData]);
const getViewportPanes = () => const getViewportPanes = () =>
layout.viewports.map((layout, viewportIndex) => { layout.viewports.map((layout, viewportIndex) => {