feat(image capture): Enhance SEG and RTSS Support with Dependency Updates and Bug Fixes (#4924)

This commit is contained in:
Alireza authored and GitHub committed 2025-04-04 12:11:29 -04:00
1 parent 479e280fdf
commit fc33bd0d59
57 files changed
+1247 -935

No files matched your search

+17 -7
View File
@@ -2,7 +2,8 @@ import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { DicomMetadataStore } from '@ohif/core';
import { useTranslation } from 'react-i18next';
import { Button, Input, Label, PanelSection, Separator } from '@ohif/ui-next';
import { Button, Input, Label, PanelSection } from '@ohif/ui-next';
import { useSystem } from '@ohif/core/src';
const DEFAULT_MEATADATA = {
PatientWeight: null,
@@ -37,7 +38,10 @@ const InputRow = ({ children, className, ...props }) => {
// InputRow sub-components
InputRow.Label = ({ children, unit, className, ...props }) => (
<Label className={`min-w-32 flex-shrink-0 ${className || ''}`} {...props}>
<Label
className={`min-w-32 flex-shrink-0 ${className || ''}`}
{...props}
>
{children}
{unit && <span className="text-muted-foreground"> {unit}</span>}
</Label>
@@ -54,7 +58,8 @@ InputRow.Input = ({ className, ...props }) => (
InputRow.Label.displayName = 'InputRow.Label';
InputRow.Input.displayName = 'InputRow.Input';
export default function PanelPetSUV({ servicesManager, commandsManager }: withAppTypes) {
export default function PanelPetSUV({ servicesManager }: withAppTypes) {
const { commandsManager } = useSystem();
const { t } = useTranslation('PanelSUV');
const { displaySetService, toolGroupService, toolbarService, hangingProtocolService } =
servicesManager.services;
@@ -192,7 +197,9 @@ export default function PanelPetSUV({ servicesManager, commandsManager }: withAp
<InputRow>
<InputRow.Label unit="bq">{t('Total Dose')}</InputRow.Label>
<InputRow.Input
value={metadata.RadiopharmaceuticalInformationSequence.RadionuclideTotalDose || ''}
value={
metadata.RadiopharmaceuticalInformationSequence.RadionuclideTotalDose || ''
}
onChange={e => {
handleMetadataChange({
RadiopharmaceuticalInformationSequence: {
@@ -206,7 +213,9 @@ export default function PanelPetSUV({ servicesManager, commandsManager }: withAp
<InputRow>
<InputRow.Label unit="s">{t('Half Life')}</InputRow.Label>
<InputRow.Input
value={metadata.RadiopharmaceuticalInformationSequence.RadionuclideHalfLife || ''}
value={
metadata.RadiopharmaceuticalInformationSequence.RadionuclideHalfLife || ''
}
onChange={e => {
handleMetadataChange({
RadiopharmaceuticalInformationSequence: {
@@ -221,7 +230,8 @@ export default function PanelPetSUV({ servicesManager, commandsManager }: withAp
<InputRow.Label unit="s">{t('Injection Time')}</InputRow.Label>
<InputRow.Input
value={
metadata.RadiopharmaceuticalInformationSequence.RadiopharmaceuticalStartTime || ''
metadata.RadiopharmaceuticalInformationSequence
.RadiopharmaceuticalStartTime || ''
}
onChange={e => {
handleMetadataChange({
@@ -269,4 +279,4 @@ PanelPetSUV.propTypes = {
}).isRequired,
}).isRequired,
}).isRequired,
};
};
@@ -2,11 +2,10 @@ import React, { useEffect } from 'react';
import { useActiveViewportSegmentationRepresentations } from '@ohif/extension-cornerstone';
import { handleROIThresholding } from '../../utils/handleROIThresholding';
import { debounce } from '@ohif/core/src/utils';
import { useSystem } from '@ohif/core/src';
export default function PanelRoiThresholdSegmentation({
servicesManager,
commandsManager,
}: withAppTypes) {
export default function PanelRoiThresholdSegmentation() {
const { commandsManager, servicesManager } = useSystem();
const { segmentationService } = servicesManager.services;
const { segmentationsWithRepresentations: segmentationsInfo } =
useActiveViewportSegmentationRepresentations({ servicesManager });
+5 -54
View File
@@ -1,62 +1,13 @@
import React from 'react';
import {
PanelSegmentation,
useActiveViewportSegmentationRepresentations,
} from '@ohif/extension-cornerstone';
import { Button, Icons } from '@ohif/ui-next';
import { PanelSegmentation } from '@ohif/extension-cornerstone';
import PanelROIThresholdExport from './PanelROIThresholdSegmentation/PanelROIThresholdExport';
export default function PanelTMTV({
servicesManager,
commandsManager,
extensionManager,
configuration,
}: withAppTypes) {
export default function PanelTMTV({ configuration }: withAppTypes) {
return (
<>
<PanelSegmentation
servicesManager={servicesManager}
commandsManager={commandsManager}
extensionManager={extensionManager}
configuration={configuration}
>
<ExportCSV
servicesManager={servicesManager}
commandsManager={commandsManager}
/>
<PanelSegmentation configuration={configuration}>
<PanelROIThresholdExport />
</PanelSegmentation>
</>
);
}
const ExportCSV = ({ servicesManager, commandsManager }: withAppTypes) => {
const { segmentationsWithRepresentations: representations } =
useActiveViewportSegmentationRepresentations({ servicesManager });
const tmtv = representations[0]?.segmentation.cachedStats?.tmtv;
const segmentations = representations.map(representation => representation.segmentation);
if (!segmentations.length) {
return null;
}
return (
<div className="flex h-8 w-full items-center rounded pr-0.5">
<Button
size="sm"
variant="ghost"
className="pl-1.5"
onClick={() => {
commandsManager.runCommand('exportTMTVReportCSV', {
segmentations,
tmtv,
config: {},
});
}}
>
<Icons.Download />
<span className="pl-1">CSV</span>
</Button>
</div>
);
};
+9 -34
View File
@@ -8,7 +8,6 @@ import createAndDownloadTMTVReport from './utils/createAndDownloadTMTVReport';
import dicomRTAnnotationExport from './utils/dicomRTAnnotationExport/RTStructureSet';
import { getWebWorkerManager } from '@cornerstonejs/core';
import { Enums } from '@cornerstonejs/tools';
import { utils } from '@ohif/core';
@@ -22,32 +21,6 @@ const ROI_THRESHOLD_MANUAL_TOOL_IDS = [
'CircleROIStartEndThreshold',
];
const workerManager = getWebWorkerManager();
// Register the task
function getVolumesFromSegmentation(segmentationId) {
const csSegmentation = csTools.segmentation.state.getSegmentation(segmentationId);
const labelmapData = csSegmentation.representationData[
SegmentationRepresentations.Labelmap
] as csTools.Types.LabelmapToolOperationDataVolume;
const { volumeId, referencedVolumeId } = labelmapData;
const labelmapVolume = cs.cache.getVolume(volumeId);
const referencedVolume = cs.cache.getVolume(referencedVolumeId);
return { labelmapVolume, referencedVolume };
}
function getLabelmapVolumeFromSegmentation(segmentation) {
const { representationData } = segmentation;
const { volumeId } = representationData[
SegmentationRepresentations.Labelmap
] as csTools.Types.LabelmapToolOperationDataVolume;
return cs.cache.getVolume(volumeId);
}
const commandsModule = ({ servicesManager, commandsManager, extensionManager }: withAppTypes) => {
const {
viewportGridService,
@@ -265,8 +238,14 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
segmentations,
});
let total_tlg = 0;
for (const segmentationId in segReport) {
const report = segReport[segmentationId];
const tlg = report['namedStats_lesionGlycolysis'];
total_tlg += tlg.value;
}
const additionalReportRows = [
{ key: 'Total Lesion Glycolysis', value: { tlg: tlg.toFixed(4) } },
{ key: 'Total Lesion Glycolysis', value: { tlg: total_tlg.toFixed(4) } },
{ key: 'Threshold Configuration', value: { ...config } },
];
@@ -382,9 +361,8 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
continue;
}
const referencedVolumeId = labelmapVolume.referencedVolumeId;
const referencedVolume = cs.cache.getVolume(referencedVolumeId);
const referencedVolume =
csTools.utilities.segmentation.getReferenceVolumeForSegmentationVolume(segmentationId);
if (!referencedVolume) {
report[id] = segReport;
@@ -476,9 +454,6 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
thresholdSegmentationByRectangleROITool: {
commandFn: actions.thresholdSegmentationByRectangleROITool,
},
getTotalLesionGlycolysis: {
commandFn: actions.getTotalLesionGlycolysis,
},
calculateTMTV: {
commandFn: actions.calculateTMTV,
},
+2 -17
View File
@@ -5,13 +5,7 @@ import PanelTMTV from './Panels/PanelTMTV';
function getPanelModule({ commandsManager, extensionManager, servicesManager }) {
const wrappedPanelPetSuv = () => {
return (
<PanelPetSUV
commandsManager={commandsManager}
servicesManager={servicesManager}
extensionManager={extensionManager}
/>
);
return <PanelPetSUV />;
};
const wrappedROIThresholdToolbox = () => {
@@ -24,12 +18,7 @@ function getPanelModule({ commandsManager, extensionManager, servicesManager })
};
const wrappedROIThresholdExport = () => {
return (
<PanelROIThresholdExport
commandsManager={commandsManager}
servicesManager={servicesManager}
/>
);
return <PanelROIThresholdExport />;
};
const wrappedPanelTMTV = () => {
@@ -43,10 +32,6 @@ function getPanelModule({ commandsManager, extensionManager, servicesManager })
commandsManager={commandsManager}
servicesManager={servicesManager}
/>
<PanelROIThresholdExport
commandsManager={commandsManager}
servicesManager={servicesManager}
/>
</>
);
};