feat(tmtv): add ct ranges for thresholding (#3225)
* Add CT volume in PET ROI Thresholding (#3053) * Add CT volume in PET ROI Thresholding * Change UI ROI Threshold config * Refactoring ROI Threshold configuration Panel * fix menus * try to fix build preview * try to fix build preview --------- Co-authored-by: rodrigobasilio2022 <114958722+rodrigobasilio2022@users.noreply.github.com>
This commit is contained in:
parent
f14e23cb8b
commit
7a591b87a2
@ -1,7 +1,6 @@
|
|||||||
import React, { useEffect, useState, useCallback, useReducer } from 'react';
|
import React, { useEffect, useState, useCallback, useReducer } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { SegmentationTable, Button, Icon } from '@ohif/ui';
|
import { SegmentationTable, Button, Icon } from '@ohif/ui';
|
||||||
import classnames from 'classnames';
|
|
||||||
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import segmentationEditHandler from './segmentationEditHandler';
|
import segmentationEditHandler from './segmentationEditHandler';
|
||||||
@ -10,14 +9,16 @@ import ROIThresholdConfiguration, {
|
|||||||
ROI_STAT,
|
ROI_STAT,
|
||||||
} from './ROIThresholdConfiguration';
|
} from './ROIThresholdConfiguration';
|
||||||
|
|
||||||
const LOWER_THRESHOLD_DEFAULT = 0;
|
const LOWER_CT_THRESHOLD_DEFAULT = -1000;
|
||||||
const UPPER_THRESHOLD_DEFAULT = 100;
|
const UPPER_CT_THRESHOLD_DEFAULT = 500;
|
||||||
|
const LOWER_PT_THRESHOLD_DEFAULT = 5;
|
||||||
|
const UPPER_PT_THRESHOLD_DEFAULT = 50;
|
||||||
const WEIGHT_DEFAULT = 0.41; // a default weight for suv max often used in the literature
|
const WEIGHT_DEFAULT = 0.41; // a default weight for suv max often used in the literature
|
||||||
const DEFAULT_STRATEGY = ROI_STAT;
|
const DEFAULT_STRATEGY = ROI_STAT;
|
||||||
|
|
||||||
function reducer(state, action) {
|
function reducer(state, action) {
|
||||||
const { payload } = action;
|
const { payload } = action;
|
||||||
const { strategy, lower, upper, weight } = payload;
|
const { strategy, ctLower, ctUpper, ptLower, ptUpper, weight } = payload;
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'setStrategy':
|
case 'setStrategy':
|
||||||
@ -28,8 +29,10 @@ function reducer(state, action) {
|
|||||||
case 'setThreshold':
|
case 'setThreshold':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
lower: lower ? lower : state.lower,
|
ctLower: ctLower ? ctLower : state.ctLower,
|
||||||
upper: upper ? upper : state.upper,
|
ctUpper: ctUpper ? ctUpper : state.ctUpper,
|
||||||
|
ptLower: ptLower ? ptLower : state.ptLower,
|
||||||
|
ptUpper: ptUpper ? ptUpper : state.ptUpper,
|
||||||
};
|
};
|
||||||
case 'setWeight':
|
case 'setWeight':
|
||||||
return {
|
return {
|
||||||
@ -57,8 +60,10 @@ export default function PanelRoiThresholdSegmentation({
|
|||||||
|
|
||||||
const [config, dispatch] = useReducer(reducer, {
|
const [config, dispatch] = useReducer(reducer, {
|
||||||
strategy: DEFAULT_STRATEGY,
|
strategy: DEFAULT_STRATEGY,
|
||||||
lower: LOWER_THRESHOLD_DEFAULT,
|
ctLower: LOWER_CT_THRESHOLD_DEFAULT,
|
||||||
upper: UPPER_THRESHOLD_DEFAULT,
|
ctUpper: UPPER_CT_THRESHOLD_DEFAULT,
|
||||||
|
ptLower: LOWER_PT_THRESHOLD_DEFAULT,
|
||||||
|
ptUpper: UPPER_PT_THRESHOLD_DEFAULT,
|
||||||
weight: WEIGHT_DEFAULT,
|
weight: WEIGHT_DEFAULT,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -171,91 +176,93 @@ export default function PanelRoiThresholdSegmentation({
|
|||||||
}, [segmentations, selectedSegmentationId]);
|
}, [segmentations, selectedSegmentationId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col">
|
<>
|
||||||
<div className="overflow-x-hidden overflow-y-auto invisible-scrollbar">
|
<div className="flex flex-col">
|
||||||
<div className="flex mx-4 my-4 mb-4 space-x-4">
|
<div className="overflow-x-hidden overflow-y-auto invisible-scrollbar">
|
||||||
<Button
|
<div className="flex mx-4 my-4 mb-4 space-x-4">
|
||||||
color="primary"
|
<Button
|
||||||
onClick={() => {
|
color="primary"
|
||||||
setLabelmapLoading(true);
|
onClick={() => {
|
||||||
setTimeout(() => {
|
setLabelmapLoading(true);
|
||||||
runCommand('createNewLabelmapFromPT').then(segmentationId => {
|
setTimeout(() => {
|
||||||
setLabelmapLoading(false);
|
runCommand('createNewLabelmapFromPT').then(segmentationId => {
|
||||||
setSelectedSegmentationId(segmentationId);
|
setLabelmapLoading(false);
|
||||||
|
setSelectedSegmentationId(segmentationId);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}}
|
||||||
|
>
|
||||||
|
{labelmapLoading ? 'loading ...' : 'New Label'}
|
||||||
|
</Button>
|
||||||
|
<Button color="primary" onClick={handleROIThresholding}>
|
||||||
|
Run
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="flex items-center justify-around h-8 mb-2 border-t outline-none cursor-pointer select-none bg-secondary-dark first:border-0 border-secondary-light"
|
||||||
|
onClick={() => {
|
||||||
|
setShowConfig(!showConfig);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{labelmapLoading ? 'loading ...' : 'New Label'}
|
<div className="px-4 text-base text-white">
|
||||||
</Button>
|
{t('ROI Threshold Configuration')}
|
||||||
<Button color="primary" onClick={handleROIThresholding}>
|
</div>
|
||||||
Run
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="flex items-center justify-around h-8 mb-2 border-t outline-none cursor-pointer select-none bg-secondary-dark first:border-0 border-secondary-light"
|
|
||||||
onClick={() => {
|
|
||||||
setShowConfig(!showConfig);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="px-4 text-base text-white">
|
|
||||||
{t('ROI Threshold Configuration')}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{showConfig && (
|
||||||
{showConfig && (
|
<ROIThresholdConfiguration
|
||||||
<ROIThresholdConfiguration
|
config={config}
|
||||||
config={config}
|
dispatch={dispatch}
|
||||||
dispatch={dispatch}
|
runCommand={runCommand}
|
||||||
runCommand={runCommand}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{/* show segmentation table */}
|
|
||||||
<div className="mt-4">
|
|
||||||
{segmentations?.length ? (
|
|
||||||
<SegmentationTable
|
|
||||||
title={t('Segmentations')}
|
|
||||||
segmentations={segmentations}
|
|
||||||
activeSegmentationId={selectedSegmentationId}
|
|
||||||
onClick={id => {
|
|
||||||
runCommand('setSegmentationActiveForToolGroups', {
|
|
||||||
segmentationId: id,
|
|
||||||
});
|
|
||||||
setSelectedSegmentationId(id);
|
|
||||||
}}
|
|
||||||
onToggleVisibility={id => {
|
|
||||||
segmentationService.toggleSegmentationVisibility(id);
|
|
||||||
}}
|
|
||||||
onToggleVisibilityAll={ids => {
|
|
||||||
ids.map(id => {
|
|
||||||
segmentationService.toggleSegmentationVisibility(id);
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
onDelete={id => {
|
|
||||||
segmentationService.remove(id);
|
|
||||||
}}
|
|
||||||
onEdit={id => {
|
|
||||||
segmentationEditHandler({
|
|
||||||
id,
|
|
||||||
servicesManager,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : null}
|
)}
|
||||||
</div>
|
{/* show segmentation table */}
|
||||||
{tmtvValue !== null ? (
|
<div className="mt-4">
|
||||||
<div className="flex items-baseline justify-between px-2 py-1 mt-4 bg-secondary-dark">
|
{segmentations?.length ? (
|
||||||
<span className="text-base font-bold tracking-widest text-white uppercase">
|
<SegmentationTable
|
||||||
{'TMTV:'}
|
title={t('Segmentations')}
|
||||||
</span>
|
segmentations={segmentations}
|
||||||
<div className="text-white">{`${tmtvValue} mL`}</div>
|
activeSegmentationId={selectedSegmentationId}
|
||||||
|
onClick={id => {
|
||||||
|
runCommand('setSegmentationActiveForToolGroups', {
|
||||||
|
segmentationId: id,
|
||||||
|
});
|
||||||
|
setSelectedSegmentationId(id);
|
||||||
|
}}
|
||||||
|
onToggleVisibility={id => {
|
||||||
|
segmentationService.toggleSegmentationVisibility(id);
|
||||||
|
}}
|
||||||
|
onToggleVisibilityAll={ids => {
|
||||||
|
ids.map(id => {
|
||||||
|
segmentationService.toggleSegmentationVisibility(id);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onDelete={id => {
|
||||||
|
segmentationService.remove(id);
|
||||||
|
}}
|
||||||
|
onEdit={id => {
|
||||||
|
segmentationEditHandler({
|
||||||
|
id,
|
||||||
|
servicesManager,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
{tmtvValue !== null ? (
|
||||||
<ExportReports
|
<div className="flex items-baseline justify-between px-2 py-1 mt-4 bg-secondary-dark">
|
||||||
segmentations={segmentations}
|
<span className="text-base font-bold tracking-widest text-white uppercase">
|
||||||
tmtvValue={tmtvValue}
|
{'TMTV:'}
|
||||||
config={config}
|
</span>
|
||||||
commandsManager={commandsManager}
|
<div className="text-white">{`${tmtvValue} mL`}</div>
|
||||||
/>
|
</div>
|
||||||
|
) : null}
|
||||||
|
<ExportReports
|
||||||
|
segmentations={segmentations}
|
||||||
|
tmtvValue={tmtvValue}
|
||||||
|
config={config}
|
||||||
|
commandsManager={commandsManager}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="opacity-50 hover:opacity-80 flex items-center justify-center text-blue-400 mt-auto cursor-pointer mb-4"
|
className="opacity-50 hover:opacity-80 flex items-center justify-center text-blue-400 mt-auto cursor-pointer mb-4"
|
||||||
@ -271,11 +278,11 @@ export default function PanelRoiThresholdSegmentation({
|
|||||||
width="15px"
|
width="15px"
|
||||||
height="15px"
|
height="15px"
|
||||||
name={'info'}
|
name={'info'}
|
||||||
className={'ml-4 mr-3 text-primary-active'}
|
className={'text-primary-active ml-4 mr-3'}
|
||||||
/>
|
/>
|
||||||
<span>{'User Guide'}</span>
|
<span>{'User Guide'}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Input, Select, Button, ButtonGroup } from '@ohif/ui';
|
import { Input, Label, Select, Button, ButtonGroup } from '@ohif/ui';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export const ROI_STAT = 'roi_stat';
|
export const ROI_STAT = 'roi_stat';
|
||||||
@ -14,9 +14,9 @@ function ROIThresholdConfiguration({ config, dispatch, runCommand }) {
|
|||||||
const { t } = useTranslation('ROIThresholdConfiguration');
|
const { t } = useTranslation('ROIThresholdConfiguration');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col px-4 space-y-4 bg-primary-dark">
|
<div className="flex flex-col px-4 space-y-4 bg-primary-dark py-2">
|
||||||
<div className="flex items-end space-x-2">
|
<div className="flex items-end space-x-2">
|
||||||
<div className="flex flex-col w-1/2 mt-2 ">
|
<div className="flex flex-col w-1/2">
|
||||||
<Select
|
<Select
|
||||||
label={t('Strategy')}
|
label={t('Strategy')}
|
||||||
closeMenuOnSelect={true}
|
closeMenuOnSelect={true}
|
||||||
@ -78,39 +78,101 @@ function ROIThresholdConfiguration({ config, dispatch, runCommand }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{config.strategy !== ROI_STAT && (
|
{config.strategy !== ROI_STAT && (
|
||||||
<div className="flex justify-between">
|
<div className="text-sm mr-2">
|
||||||
<Input
|
<table>
|
||||||
label={t('Lower')}
|
<tbody>
|
||||||
labelClassName="text-white"
|
<tr className="mt-2">
|
||||||
className="mt-2 bg-black border-primary-main"
|
<td className="pr-4 pt-2" colSpan="3">
|
||||||
type="text"
|
<Label
|
||||||
containerClassName="mr-2"
|
className="text-white"
|
||||||
value={config.lower}
|
text="Lower & Upper Ranges"
|
||||||
onChange={e => {
|
></Label>
|
||||||
dispatch({
|
</td>
|
||||||
type: 'setThreshold',
|
</tr>
|
||||||
payload: {
|
<tr className="mt-2">
|
||||||
lower: e.target.value,
|
<td className="text-center pr-4 pt-2">
|
||||||
},
|
<Label className="text-white" text="CT"></Label>
|
||||||
});
|
</td>
|
||||||
}}
|
<td>
|
||||||
/>
|
<div className="flex justify-between">
|
||||||
<Input
|
<Input
|
||||||
label={t('Upper')}
|
label={t('')}
|
||||||
labelClassName="text-white"
|
labelClassName="text-white"
|
||||||
className="mt-2 bg-black border-primary-main"
|
className="mt-2 bg-black border-primary-main"
|
||||||
type="text"
|
type="text"
|
||||||
containerClassName="mr-2"
|
containerClassName="mr-2"
|
||||||
value={config.upper}
|
value={config.ctLower}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'setThreshold',
|
type: 'setThreshold',
|
||||||
payload: {
|
payload: {
|
||||||
upper: e.target.value,
|
ctLower: e.target.value,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Input
|
||||||
|
label={t('')}
|
||||||
|
labelClassName="text-white"
|
||||||
|
className="mt-2 bg-black border-primary-main"
|
||||||
|
type="text"
|
||||||
|
containerClassName="mr-2"
|
||||||
|
value={config.ctUpper}
|
||||||
|
onChange={e => {
|
||||||
|
dispatch({
|
||||||
|
type: 'setThreshold',
|
||||||
|
payload: {
|
||||||
|
ctUpper: e.target.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td className="text-center pr-4 pt-2">
|
||||||
|
<Label className="text-white" text="PT"></Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<Input
|
||||||
|
label={t('')}
|
||||||
|
labelClassName="text-white"
|
||||||
|
className="mt-2 bg-black border-primary-main"
|
||||||
|
type="text"
|
||||||
|
containerClassName="mr-2"
|
||||||
|
value={config.ptLower}
|
||||||
|
onChange={e => {
|
||||||
|
dispatch({
|
||||||
|
type: 'setThreshold',
|
||||||
|
payload: {
|
||||||
|
ptLower: e.target.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
label={t('')}
|
||||||
|
labelClassName="text-white"
|
||||||
|
className="mt-2 bg-black border-primary-main"
|
||||||
|
type="text"
|
||||||
|
containerClassName="mr-2"
|
||||||
|
value={config.ptUpper}
|
||||||
|
onChange={e => {
|
||||||
|
dispatch({
|
||||||
|
type: 'setThreshold',
|
||||||
|
payload: {
|
||||||
|
ptUpper: e.target.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -173,12 +173,20 @@ const commandsModule = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { representationData } = segmentation;
|
const { representationData } = segmentation;
|
||||||
const { volumeId: segVolumeId } = representationData[LABELMAP];
|
const {
|
||||||
|
displaySetMatchDetails: matchDetails,
|
||||||
|
} = hangingProtocolService.getMatchDetails();
|
||||||
|
const volumeLoaderScheme = 'cornerstoneStreamingImageVolume'; // Loader id which defines which volume loader to use
|
||||||
|
|
||||||
|
const ctDisplaySet = matchDetails.get('ctDisplaySet');
|
||||||
|
const ctVolumeId = `${volumeLoaderScheme}:${ctDisplaySet.displaySetInstanceUID}`; // VolumeId with loader id + volume id
|
||||||
|
|
||||||
|
const { volumeId: segVolumeId } = representationData[LABELMAP];
|
||||||
const { referencedVolumeId } = cs.cache.getVolume(segVolumeId);
|
const { referencedVolumeId } = cs.cache.getVolume(segVolumeId);
|
||||||
|
|
||||||
const labelmapVolume = cs.cache.getVolume(segmentationId);
|
const labelmapVolume = cs.cache.getVolume(segmentationId);
|
||||||
const referencedVolume = cs.cache.getVolume(referencedVolumeId);
|
const referencedVolume = cs.cache.getVolume(referencedVolumeId);
|
||||||
|
const ctReferencedVolume = cs.cache.getVolume(ctVolumeId);
|
||||||
|
|
||||||
if (!referencedVolume) {
|
if (!referencedVolume) {
|
||||||
throw new Error('No Reference volume found');
|
throw new Error('No Reference volume found');
|
||||||
@ -201,23 +209,20 @@ const commandsModule = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { lower, upper } = getThresholdValues(
|
const { ptLower, ptUpper, ctLower, ctUpper } = getThresholdValues(
|
||||||
annotationUIDs,
|
annotationUIDs,
|
||||||
referencedVolume,
|
[referencedVolume, ctReferencedVolume],
|
||||||
config
|
config
|
||||||
);
|
);
|
||||||
|
|
||||||
const configToUse = {
|
|
||||||
lower,
|
|
||||||
upper,
|
|
||||||
overwrite: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
return csTools.utilities.segmentation.rectangleROIThresholdVolumeByRange(
|
return csTools.utilities.segmentation.rectangleROIThresholdVolumeByRange(
|
||||||
annotationUIDs,
|
annotationUIDs,
|
||||||
labelmapVolume,
|
labelmapVolume,
|
||||||
[referencedVolume],
|
[
|
||||||
configToUse
|
{ volume: referencedVolume, lower: ptLower, upper: ptUpper },
|
||||||
|
{ volume: ctReferencedVolume, lower: ctLower, upper: ctUpper },
|
||||||
|
],
|
||||||
|
{ overwrite: true }
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
calculateSuvPeak: ({ labelmap }) => {
|
calculateSuvPeak: ({ labelmap }) => {
|
||||||
|
|||||||
@ -1,19 +1,7 @@
|
|||||||
import * as csTools from '@cornerstonejs/tools';
|
import * as csTools from '@cornerstonejs/tools';
|
||||||
|
|
||||||
function getThresholdValues(
|
function getRoiStats(referencedVolume, annotations) {
|
||||||
annotationUIDs,
|
|
||||||
referencedVolume,
|
|
||||||
config
|
|
||||||
): { lower: number; upper: number } {
|
|
||||||
if (config.strategy === 'range') {
|
|
||||||
return {
|
|
||||||
lower: Number(config.lower),
|
|
||||||
upper: Number(config.upper),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// roiStats
|
// roiStats
|
||||||
const { weight } = config;
|
|
||||||
const { imageData } = referencedVolume;
|
const { imageData } = referencedVolume;
|
||||||
const values = imageData
|
const values = imageData
|
||||||
.getPointData()
|
.getPointData()
|
||||||
@ -24,10 +12,6 @@ function getThresholdValues(
|
|||||||
const { fn, baseValue } = _getStrategyFn('max');
|
const { fn, baseValue } = _getStrategyFn('max');
|
||||||
let value = baseValue;
|
let value = baseValue;
|
||||||
|
|
||||||
const annotations = annotationUIDs.map(annotationUID =>
|
|
||||||
csTools.annotation.state.getAnnotation(annotationUID)
|
|
||||||
);
|
|
||||||
|
|
||||||
const boundsIJK = csTools.utilities.rectangleROITool.getBoundsIJKFromRectangleAnnotations(
|
const boundsIJK = csTools.utilities.rectangleROITool.getBoundsIJKFromRectangleAnnotations(
|
||||||
annotations,
|
annotations,
|
||||||
referencedVolume
|
referencedVolume
|
||||||
@ -43,10 +27,36 @@ function getThresholdValues(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getThresholdValues(
|
||||||
|
annotationUIDs,
|
||||||
|
referencedVolumes,
|
||||||
|
config
|
||||||
|
): { ptLower: number; ptUpper: number; ctLower: number; ctUpper: number } {
|
||||||
|
if (config.strategy === 'range') {
|
||||||
|
return {
|
||||||
|
ptLower: Number(config.ptLower),
|
||||||
|
ptUpper: Number(config.ptUpper),
|
||||||
|
ctLower: Number(config.ctLower),
|
||||||
|
ctUpper: Number(config.ctUpper),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { weight } = config;
|
||||||
|
const annotations = annotationUIDs.map(annotationUID =>
|
||||||
|
csTools.annotation.state.getAnnotation(annotationUID)
|
||||||
|
);
|
||||||
|
|
||||||
|
const ptValue = getRoiStats(referencedVolumes[0], annotations);
|
||||||
|
const ctValue = getRoiStats(referencedVolumes[1], annotations);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
lower: weight * value,
|
ctLower: weight * ctValue,
|
||||||
upper: +Infinity,
|
ctUpper: +Infinity,
|
||||||
|
ptLower: weight * ptValue,
|
||||||
|
ptUpper: +Infinity,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
base = ""
|
base = ""
|
||||||
build = "yarn run build:viewer:ci"
|
build = "yarn run build:viewer:ci"
|
||||||
publish = "dist"
|
publish = "dist"
|
||||||
ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF . ../ui/ ../core/ ../i18n ../../extensions/ ../../modes"
|
ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF . ../ui/ ../core/ ../i18n"
|
||||||
|
|
||||||
|
|
||||||
# NODE_VERSION in root `.nvmrc` takes priority
|
# NODE_VERSION in root `.nvmrc` takes priority
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user