Fix IDC Re #2918: Runtime tolerance for SEGs loading (#2924)

This commit is contained in:
Davide Punzo 2022-09-12 14:22:32 +02:00 committed by GitHub
parent ebbc9e0d6d
commit e0fb439e98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 79 additions and 11 deletions

View File

@ -36,6 +36,7 @@ const { studyMetadataManager } = utils;
* @param {Function} props.onConfigurationChange - Configuration change handler * @param {Function} props.onConfigurationChange - Configuration change handler
* @param {Function} props.activeContexts - List of active application contexts * @param {Function} props.activeContexts - List of active application contexts
* @param {Function} props.contexts - List of available application contexts * @param {Function} props.contexts - List of available application contexts
* @param {Function} props.servicesManager - Services manager
* @returns component * @returns component
*/ */
const SegmentationPanel = ({ const SegmentationPanel = ({
@ -50,6 +51,7 @@ const SegmentationPanel = ({
onSelectedSegmentationChange, onSelectedSegmentationChange,
activeContexts = [], activeContexts = [],
contexts = {}, contexts = {},
servicesManager,
}) => { }) => {
const isVTK = () => activeContexts.includes(contexts.VTK); const isVTK = () => activeContexts.includes(contexts.VTK);
const isCornerstone = () => activeContexts.includes(contexts.CORNERSTONE); const isCornerstone = () => activeContexts.includes(contexts.CORNERSTONE);
@ -59,6 +61,9 @@ const SegmentationPanel = ({
* store with context to make these kind of things less blurry. * store with context to make these kind of things less blurry.
*/ */
const { configuration } = cornerstoneTools.getModule('segmentation'); const { configuration } = cornerstoneTools.getModule('segmentation');
if (configuration.segsTolerance === undefined) {
configuration.segsTolerance = 1e-2;
}
const DEFAULT_BRUSH_RADIUS = configuration.radius || 10; const DEFAULT_BRUSH_RADIUS = configuration.radius || 10;
/* /*
@ -87,6 +92,25 @@ const SegmentationPanel = ({
return studyMetadata.getFirstImageId(displaySetInstanceUID); return studyMetadata.getFirstImageId(displaySetInstanceUID);
}; };
const getAllSegDisplaySets = () => {
const { StudyInstanceUID } = getActiveViewport();
const studyMetadata = studyMetadataManager.get(StudyInstanceUID);
return studyMetadata.getDerivedDatasets({
Modality: 'SEG',
});
};
const updateSegDisplaySetsTolerance = tolerance => {
const segDisplaySets = getAllSegDisplaySets();
segDisplaySets.forEach(segDisplaySet => {
// update tol value
segDisplaySet.tolerance = tolerance;
// reset load flags for allowing retry for seg parsing.
segDisplaySet.isLoaded = false;
segDisplaySet.loadError = false;
});
};
const getActiveLabelMaps3D = () => { const getActiveLabelMaps3D = () => {
const { labelmaps3D, activeLabelmapIndex } = getBrushStackState(); const { labelmaps3D, activeLabelmapIndex } = getBrushStackState();
return labelmaps3D[activeLabelmapIndex]; return labelmaps3D[activeLabelmapIndex];
@ -598,7 +622,9 @@ const SegmentationPanel = ({
configuration.outlineWidth = newConfiguration.outlineWidth; configuration.outlineWidth = newConfiguration.outlineWidth;
configuration.fillAlphaInactive = newConfiguration.fillAlphaInactive; configuration.fillAlphaInactive = newConfiguration.fillAlphaInactive;
configuration.outlineAlphaInactive = newConfiguration.outlineAlphaInactive; configuration.outlineAlphaInactive = newConfiguration.outlineAlphaInactive;
configuration.segsTolerance = newConfiguration.segsTolerance;
onConfigurationChange(newConfiguration); onConfigurationChange(newConfiguration);
updateSegDisplaySetsTolerance(configuration.segsTolerance);
refreshViewports(); refreshViewports();
}; };
@ -647,6 +673,7 @@ const SegmentationPanel = ({
configuration={configuration} configuration={configuration}
onBack={() => setState(state => ({ ...state, showSettings: false }))} onBack={() => setState(state => ({ ...state, showSettings: false }))}
onChange={updateConfiguration} onChange={updateConfiguration}
servicesManager={servicesManager}
/> />
); );
} else { } else {

View File

@ -4,7 +4,7 @@ import { Range } from '@ohif/ui';
import './SegmentationSettings.css'; import './SegmentationSettings.css';
const SegmentationSettings = ({ configuration, onBack, onChange, disabledFields = [] }) => { const SegmentationSettings = ({ configuration, onBack, onChange, servicesManager, disabledFields = [] }) => {
const [state, setState] = useState({ const [state, setState] = useState({
renderFill: configuration.renderFill, renderFill: configuration.renderFill,
renderOutline: configuration.renderOutline, renderOutline: configuration.renderOutline,
@ -13,7 +13,8 @@ const SegmentationSettings = ({ configuration, onBack, onChange, disabledFields
outlineAlpha: configuration.outlineAlpha, outlineAlpha: configuration.outlineAlpha,
outlineWidth: configuration.outlineWidth, outlineWidth: configuration.outlineWidth,
fillAlphaInactive: configuration.fillAlphaInactive, fillAlphaInactive: configuration.fillAlphaInactive,
outlineAlphaInactive: configuration.outlineAlphaInactive outlineAlphaInactive: configuration.outlineAlphaInactive,
segsTolerance: configuration.segsTolerance,
}); });
useEffect(() => { useEffect(() => {
@ -133,6 +134,40 @@ const SegmentationSettings = ({ configuration, onBack, onChange, disabledFields
)} )}
</div> </div>
)} )}
<div className="settings-group" style={{ marginBottom: 15 }}>
<label style={{ margin: '0 15px' }}>
Tolerance:
<input
style={{ margin: '0 15px' }}
label="Tolerance"
onKeyPress={event => {
const validate = string => {
let rgx = /[^-.e0-9]+/g;
return string.match(rgx);
};
if (validate(event.key)) {
event.preventDefault();
}
}}
onChange={event => {
save('segsTolerance', event.target.value);
const { UINotificationService, LoggerService } = servicesManager.services;
const error = new Error('Segmentation loader tolerance changed. This operation can potentially generate errors in the Segmentation parsing.');
LoggerService.error({ error, message: error.message });
UINotificationService.show({
title: 'Segmentation panel',
message: error.message,
type: 'warning',
autoClose: true,
});
}
}
value={state.segsTolerance}
/>
</label>
</div>
</div> </div>
); );
}; };
@ -169,11 +204,12 @@ SegmentationSettings.propTypes = {
renderFill: PropTypes.bool.isRequired, renderFill: PropTypes.bool.isRequired,
renderOutline: PropTypes.bool.isRequired, renderOutline: PropTypes.bool.isRequired,
shouldRenderInactiveLabelmaps: PropTypes.bool.isRequired, shouldRenderInactiveLabelmaps: PropTypes.bool.isRequired,
fillAlpha: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, /* TODO: why fillAlpha is string? */ fillAlpha: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
outlineAlpha: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, /* TODO: why fillAlpha is string? */ outlineAlpha: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
outlineWidth: PropTypes.number.isRequired, outlineWidth: PropTypes.number.isRequired,
fillAlphaInactive: PropTypes.number.isRequired, fillAlphaInactive: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
outlineAlphaInactive: PropTypes.number.isRequired, outlineAlphaInactive: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
segsTolerance: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
}).isRequired, }).isRequired,
onBack: PropTypes.func.isRequired, onBack: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,

View File

@ -62,6 +62,7 @@ export default function getSopClassHandlerModule({ servicesManager }) {
SeriesNumber, SeriesNumber,
SeriesDescription, SeriesDescription,
metadata, metadata,
tolerance: 1e-2,
}; };
segDisplaySet.getSourceDisplaySet = function( segDisplaySet.getSourceDisplaySet = function(
@ -93,7 +94,7 @@ export default function getSopClassHandlerModule({ servicesManager }) {
referencedDisplaySet.SeriesInstanceUID referencedDisplaySet.SeriesInstanceUID
); );
const results = await _parseSeg(segArrayBuffer, imageIds); const results = await _parseSeg(segArrayBuffer, imageIds, segDisplaySet.tolerance);
if (results === undefined) { if (results === undefined) {
return; return;
} }
@ -149,10 +150,13 @@ export default function getSopClassHandlerModule({ servicesManager }) {
}; };
} }
function _parseSeg(arrayBuffer, imageIds) { function _parseSeg(
const skipOverlapping = false; arrayBuffer,
const tolerance = 1e-2; imageIds,
const cornerstoneToolsVersion = 4; tolerance = 1e-2,
skipOverlapping = false,
cornerstoneToolsVersion = 4
) {
return dcmjs.adapters.Cornerstone.Segmentation.generateToolState( return dcmjs.adapters.Cornerstone.Segmentation.generateToolState(
imageIds, imageIds,
arrayBuffer, arrayBuffer,

View File

@ -78,6 +78,7 @@ export default {
onConfigurationChange={onConfigurationChangeHandler} onConfigurationChange={onConfigurationChangeHandler}
onSelectedSegmentationChange={onSelectedSegmentationChangeHandler} onSelectedSegmentationChange={onSelectedSegmentationChangeHandler}
onDisplaySetLoadFailure={onDisplaySetLoadFailureHandler} onDisplaySetLoadFailure={onDisplaySetLoadFailureHandler}
servicesManager={servicesManager}
/> />
); );
}; };