fix: segmentation not loading (#1566)
* Fix bug * Refactor the state of the component RTPanel
This commit is contained in:
parent
333677c40e
commit
4a7ce1c093
@ -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,
|
||||||
|
|||||||
@ -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];
|
||||||
|
|
||||||
const labelmap3D =
|
if (brushStackState) {
|
||||||
brushStackState.labelmaps3D[brushStackState.activeLabelmapIndex];
|
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]);
|
||||||
|
|
||||||
/*
|
/* Handle open/closed panel behaviour */
|
||||||
* 2. UseEffect to update state? or to a least trigger a re-render
|
useEffect(() => {
|
||||||
* 4. Toggle visibility of labelmap?
|
updateState('showSegSettings', state.showSegSettings && !isOpen);
|
||||||
* 5. Toggle visibility of seg?
|
}, [isOpen]);
|
||||||
*
|
|
||||||
* 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 = () => {
|
const getLabelmapList = (brushStackState, firstImageId, activeViewport) => {
|
||||||
/* 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();
|
||||||
|
|||||||
@ -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
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user