Description
Is your enhancement request related to a problem? Please describe.
When running the MONAI CT TotalSegmentator MAP pipeline pythonically on an internal hospital study, the following error is produced by highdicom
via the DICOMSegmentationWriterOperator
:
(ct-totalsegmentator) bluna301@EW22-04661:~/ct-totalsegmentator-map$ ./scripts/model_run.sh
[info] [fragment.cpp:599] Loading extensions from configs...
[2025-04-02 09:44:27,202] [INFO] (root) - Parsed args: Namespace(log_level=None, input=PosixPath('/home/bluna301/ct-totalsegmentator-map/dicom_data/duplicate'), output=PosixPath('/home/bluna301/ct-totalsegmentator-map/output'), model=PosixPath('/home/bluna301/ct-totalsegmentator-map/model/model.ts'), workdir=None, argv=['my_app', '-i', '/home/bluna301/ct-totalsegmentator-map/dicom_data/duplicate', '-o', '/home/bluna301/ct-totalsegmentator-map/output', '-m', '/home/bluna301/ct-totalsegmentator-map/model/model.ts'])
[2025-04-02 09:44:27,202] [INFO] (root) - AppContext object: AppContext(input_path=/home/bluna301/ct-totalsegmentator-map/dicom_data/duplicate, output_path=/home/bluna301/ct-totalsegmentator-map/output, model_path=/home/bluna301/ct-totalsegmentator-map/model/model.ts, workdir=)
[2025-04-02 09:44:27,219] [INFO] (root) - End compose
[info] [gxf_executor.cpp:264] Creating context
[info] [gxf_executor.cpp:1797] creating input IOSpec named 'input_folder'
[info] [gxf_executor.cpp:1797] creating input IOSpec named 'dicom_study_list'
[info] [gxf_executor.cpp:1797] creating input IOSpec named 'study_selected_series_list'
[info] [gxf_executor.cpp:1797] creating input IOSpec named 'image'
[info] [gxf_executor.cpp:1797] creating input IOSpec named 'study_selected_series_list'
[info] [gxf_executor.cpp:1797] creating input IOSpec named 'text'
[info] [gxf_executor.cpp:1797] creating input IOSpec named 'output_folder'
[info] [gxf_executor.cpp:1797] creating input IOSpec named 'study_selected_series_list'
[info] [gxf_executor.cpp:1797] creating input IOSpec named 'seg_image'
[info] [gxf_executor.cpp:2208] Activating Graph...
[info] [gxf_executor.cpp:2238] Running Graph...
[info] [gxf_executor.cpp:2240] Waiting for completion...
[info] [greedy_scheduler.cpp:191] Scheduling 6 entities
[2025-04-02 09:44:27,347] [INFO] (monai.deploy.operators.dicom_data_loader_operator.DICOMDataLoaderOperator) - No or invalid input path from the optional input port: None
[2025-04-02 09:44:27,812] [INFO] (root) - Finding series for Selection named: Standard Axial CT Series
[2025-04-02 09:44:27,813] [INFO] (root) - Searching study, : 1.2.840.113619.2.405.3.185216268.497.1730719949.224
# of series: 1
[2025-04-02 09:44:27,813] [INFO] (root) - Working on series, instance UID: 1.2.840.113619.2.405.3.185216268.497.1730719949.233
[2025-04-02 09:44:27,813] [INFO] (root) - On attribute: 'StudyDescription' to match value: '(.*?)'
[2025-04-02 09:44:27,813] [INFO] (root) - Series attribute StudyDescription value: NM FDG PET CT SKULL TO MID THIGH AND CT N/C WITH CONTRAST
[2025-04-02 09:44:27,813] [INFO] (root) - Series attribute string value did not match. Try regEx.
[2025-04-02 09:44:27,813] [INFO] (root) - On attribute: 'Modality' to match value: '(?i)CT'
[2025-04-02 09:44:27,813] [INFO] (root) - Series attribute Modality value: CT
[2025-04-02 09:44:27,813] [INFO] (root) - Series attribute string value did not match. Try regEx.
[2025-04-02 09:44:27,813] [INFO] (root) - On attribute: 'ImageType' to match value: ['PRIMARY', 'ORIGINAL', 'AXIAL']
[2025-04-02 09:44:27,813] [INFO] (root) - Series attribute ImageType value: None
[2025-04-02 09:44:27,813] [INFO] (root) - On attribute: 'SliceThickness' to match value: [2, 5]
[2025-04-02 09:44:27,813] [INFO] (root) - Series attribute SliceThickness value: None
[2025-04-02 09:44:27,813] [INFO] (root) - On attribute: 'SeriesDescription' to match value: '(?i)^(?!.*(cor|sag)).*$'
[2025-04-02 09:44:27,814] [INFO] (root) - Series attribute SeriesDescription value: LDCT
[2025-04-02 09:44:27,814] [INFO] (root) - Series attribute string value did not match. Try regEx.
[2025-04-02 09:44:27,814] [INFO] (root) - Selected Series, UID: 1.2.840.113619.2.405.3.185216268.497.1730719949.233
[2025-04-02 09:44:27,814] [INFO] (root) - Series Selection finalized.
[2025-04-02 09:44:27,814] [INFO] (root) - Series Description of selected DICOM Series for inference: LDCT
[2025-04-02 09:44:27,814] [INFO] (root) - Series Instance UID of selected DICOM Series for inference: 1.2.840.113619.2.405.3.185216268.497.1730719949.233
[2025-04-02 09:44:35,110] [INFO] (ct_totalseg_operator.CTTotalSegOperator) - TorchScript model detected
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - Converted Image object metadata:
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesInstanceUID: 1.2.840.113619.2.405.3.185216268.497.1730719949.233, type <class 'str'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesDate: 20241111, type <class 'str'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesTime: 143622.000, type <class 'str'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - Modality: CT, type <class 'str'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesDescription: LDCT, type <class 'str'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - PatientPosition: FFS, type <class 'str'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesNumber: 2, type <class 'int'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - row_pixel_spacing: 0.976562, type <class 'float'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - col_pixel_spacing: 0.976562, type <class 'float'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - depth_pixel_spacing: 3.75, type <class 'float'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - row_direction_cosine: [1.0, 0.0, 0.0], type <class 'list'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - col_direction_cosine: [0.0, 1.0, 0.0], type <class 'list'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - depth_direction_cosine: [0.0, 0.0, 1.0], type <class 'list'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - dicom_affine_transform: [[ 9.76562000e-01 0.00000000e+00 0.00000000e+00 -2.50000000e+02]
[ 0.00000000e+00 9.76562000e-01 0.00000000e+00 -2.50000000e+02]
[ 0.00000000e+00 0.00000000e+00 3.72631833e+00 -1.32750000e+03]
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00]], type <class 'numpy.ndarray'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - nifti_affine_transform: [[-9.76562000e-01 -0.00000000e+00 -0.00000000e+00 2.50000000e+02]
[-0.00000000e+00 -9.76562000e-01 -0.00000000e+00 2.50000000e+02]
[ 0.00000000e+00 0.00000000e+00 3.72631833e+00 -1.32750000e+03]
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00]], type <class 'numpy.ndarray'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyInstanceUID: 1.2.840.113619.2.405.3.185216268.497.1730719949.224, type <class 'str'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyID: 5675, type <class 'str'>
[2025-04-02 09:44:35,111] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyDate: 20241111, type <class 'str'>
[2025-04-02 09:44:35,112] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyTime: 143203.000, type <class 'str'>
[2025-04-02 09:44:35,112] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyDescription: NM FDG PET CT SKULL TO MID THIGH AND CT N/C WITH CONTRAST, type <class 'str'>
[2025-04-02 09:44:35,112] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - AccessionNumber: 11144480, type <class 'str'>
[2025-04-02 09:44:35,112] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - selection_name: Standard Axial CT Series, type <class 'str'>
[2025-04-02 09:44:39,779] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - Input of <class 'monai.data.meta_tensor.MetaTensor'> shape: torch.Size([1, 1, 334, 334, 774])
[2025-04-02 09:53:17,500] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - Post transform length/batch size of output: 1
[2025-04-02 09:53:17,827] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - Post transform pixel spacings for pred: tensor([0.9766, 0.9766, 3.7263], dtype=torch.float64)
[2025-04-02 09:53:17,828] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - Post transform pred of <class 'numpy.ndarray'> shape: (1, 512, 512, 312)
[2025-04-02 09:53:17,854] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - Output Seg image numpy array of type <class 'numpy.ndarray'> shape: (312, 512, 512)
[2025-04-02 09:53:17,861] [INFO] (monai_seg_inference_operator.MonaiSegInferenceOperator) - Output Seg image pixel max value: 104
[2025-04-02 09:53:18,488] [INFO] (root) - Finished writing DICOM instance to file /home/bluna301/ct-totalsegmentator-map/output/SR/1.2.826.0.1.3680043.8.498.47870571337236747815607421787958144492.dcm
[2025-04-02 09:53:18,496] [INFO] (monai.deploy.operators.dicom_text_sr_writer_operator.DICOMTextSRWriterOperator) - DICOM SOP instance saved in /home/bluna301/ct-totalsegmentator-map/output/SR/1.2.826.0.1.3680043.8.498.47870571337236747815607421787958144492.dcm
[error] [gxf_wrapper.cpp:100] Exception occurred for operator: 'dicom_seg_writer' - ValueError: Input image/frame positions are not unique according to the Dimension Index Pointers. The generated segmentation would be ambiguous. Ensure that source images/frames have distinct locations.
At:
/home/bluna301/miniconda3/envs/ct-totalsegmentator/lib/python3.9/site-packages/highdicom/seg/content.py(668): get_index_values
/home/bluna301/miniconda3/envs/ct-totalsegmentator/lib/python3.9/site-packages/highdicom/seg/sop.py(1829): __init__
/home/bluna301/miniconda3/envs/ct-totalsegmentator/lib/python3.9/site-packages/monai/deploy/operators/dicom_seg_writer_operator.py(318): create_dicom_seg
/home/bluna301/miniconda3/envs/ct-totalsegmentator/lib/python3.9/site-packages/monai/deploy/operators/dicom_seg_writer_operator.py(301): process_images
/home/bluna301/miniconda3/envs/ct-totalsegmentator/lib/python3.9/site-packages/monai/deploy/operators/dicom_seg_writer_operator.py(280): compute
[error] [entity_executor.cpp:596] Failed to tick codelet dicom_seg_writer in entity: dicom_seg_writer code: GXF_FAILURE
[warning] [greedy_scheduler.cpp:243] Error while executing entity 41 named 'dicom_seg_writer': GXF_FAILURE
[info] [greedy_scheduler.cpp:401] Scheduler finished.
[error] [program.cpp:580] wait failed. Deactivating...
[error] [runtime.cpp:1649] Graph wait failed with error: GXF_FAILURE
[warning] [gxf_executor.cpp:2241] GXF call GxfGraphWait(context) in line 2241 of file /workspace/holoscan-sdk/src/core/executors/gxf/gxf_executor.cpp failed with 'GXF_FAILURE' (1)
[info] [gxf_executor.cpp:2251] Graph execution finished.
[error] [gxf_executor.cpp:2259] Graph execution error: GXF_FAILURE
Traceback (most recent call last):
File "/home/bluna301/miniconda3/envs/ct-totalsegmentator/lib/python3.9/runpy.py", line 197, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/home/bluna301/miniconda3/envs/ct-totalsegmentator/lib/python3.9/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "/home/bluna301/ct-totalsegmentator-map/my_app/__main__.py", line 25, in <module>
CTTotalSegmentatorApp().run()
File "/home/bluna301/ct-totalsegmentator-map/my_app/app.py", line 63, in run
super().run(*args, **kwargs)
File "/home/bluna301/miniconda3/envs/ct-totalsegmentator/lib/python3.9/site-packages/monai/deploy/operators/dicom_seg_writer_operator.py", line 280, in compute
self.process_images(seg_image, study_selected_series_list, output_folder)
File "/home/bluna301/miniconda3/envs/ct-totalsegmentator/lib/python3.9/site-packages/monai/deploy/operators/dicom_seg_writer_operator.py", line 301, in process_images
self.create_dicom_seg(seg_image_numpy, dicom_series, output_dir)
File "/home/bluna301/miniconda3/envs/ct-totalsegmentator/lib/python3.9/site-packages/monai/deploy/operators/dicom_seg_writer_operator.py", line 318, in create_dicom_seg
seg = hd.seg.Segmentation(
File "/home/bluna301/miniconda3/envs/ct-totalsegmentator/lib/python3.9/site-packages/highdicom/seg/sop.py", line 1829, in __init__
self.DimensionIndexSequence.get_index_values(
File "/home/bluna301/miniconda3/envs/ct-totalsegmentator/lib/python3.9/site-packages/highdicom/seg/content.py", line 668, in get_index_values
raise ValueError(
ValueError: Input image/frame positions are not unique according to the Dimension Index Pointers. The generated segmentation would be ambiguous. Ensure that source images/frames have distinct locations.
Through parsing the DICOMSegmentationWriterOperator and the highdicom source code, it was determined that this error is caused by the input DICOM Series having multiple SOP instances with duplicate spatial coordinates (i.e. SliceLocation
and ImagePositionPatient
tags).
For this specific case, two SOP instances (Image #'s 156 and 157) have the exact same spatial coordinates:
SliceLocation
:-746.25
ImagePositionPatient
:[-250.000, -250.000, -746.250]
While they have the same spatial coordinates, the images do not appear visually identical (although they are very similar):
One explanation for the duplicate slices could be that this DICOM Series is a whole-body CT scan (312 total SOP instances) that has multiple AcquisitionNumber
values (1-3) throughout the series (see below when DICOM Series is loaded in 3D Slicer). The duplicate slices occur at the most inferior slice of AcquisitionNumber
= 2, and the most superior slice of AcquisitionNumber
= 3.
Describe the solution you'd like
Ideally, there would be a way within MONAI Deploy App SDK to account for slices with duplicate spatial coordinates, perhaps by deleting one of the duplicate instances or by "skipping" that slice location and deleting both duplicates. Considering the DICOMSegmentationWriterOperator
depends on highdicom
, it may be easiest to employ a fix within the DICOMSeriesToVolumeOperator
, perhaps within the prepare_series
method where there is already existing functionality to remove slices.
Describe alternatives you've considered
Updating highdicom
to account for duplicate input slices.
Additional context
Additional background on slices with duplicate spatial coordinates.