1- # Copyright 2021-2023 MONAI Consortium
1+ # Copyright 2021-2025 MONAI Consortium
22# Licensed under the Apache License, Version 2.0 (the "License");
33# you may not use this file except in compliance with the License.
44# You may obtain a copy of the License at
2727ImplicitVRLittleEndian , _ = optional_import ("pydicom.uid" , name = "ImplicitVRLittleEndian" )
2828Dataset , _ = optional_import ("pydicom.dataset" , name = "Dataset" )
2929FileDataset , _ = optional_import ("pydicom.dataset" , name = "FileDataset" )
30+ PyDicomSequence , _ = optional_import ("pydicom.sequence" , name = "Sequence" )
3031sitk , _ = optional_import ("SimpleITK" )
3132codes , _ = optional_import ("pydicom.sr.codedict" , name = "codes" )
3233if TYPE_CHECKING :
3940from monai .deploy .core import ConditionType , Fragment , Image , Operator , OperatorSpec
4041from monai .deploy .core .domain .dicom_series import DICOMSeries
4142from monai .deploy .core .domain .dicom_series_selection import StudySelectedSeries
43+ from monai .deploy .operators .dicom_utils import ModelInfo
4244
4345
4446class SegmentDescription :
@@ -183,6 +185,7 @@ def __init__(
183185 * args ,
184186 segment_descriptions : List [SegmentDescription ],
185187 output_folder : Path ,
188+ model_info : Optional [ModelInfo ] = None ,
186189 custom_tags : Optional [Dict [str , str ]] = None ,
187190 omit_empty_frames : bool = True ,
188191 ** kwargs ,
@@ -206,6 +209,7 @@ def __init__(
206209 Object encapsulating the description of each segment present in the segmentation.
207210 output_folder: Folder for file output, overridden by named input on compute.
208211 Defaults to current working dir's child folder, output.
212+ model_info (ModelInfo, optional): Object encapsulating model creator, name, version and UID.
209213 custom_tags: Optional[Dict[str, str]], optional
210214 Dictionary for setting custom DICOM tags using Keywords and str values only
211215 omit_empty_frames: bool, optional
@@ -217,6 +221,7 @@ def __init__(
217221 self ._custom_tags = custom_tags
218222 self ._omit_empty_frames = omit_empty_frames
219223 self .output_folder = output_folder if output_folder else DICOMSegmentationWriterOperator .DEFAULT_OUTPUT_FOLDER
224+ self .model_info = model_info if model_info else ModelInfo ()
220225
221226 self .input_name_seg = "seg_image"
222227 self .input_name_series = "study_selected_series_list"
@@ -356,6 +361,41 @@ def create_dicom_seg(self, image: np.ndarray, dicom_series: DICOMSeries, output_
356361 # Best effort for now.
357362 logging .warning (f"Tag { k } was not written, due to { ex } " )
358363
364+ # write model info
365+ # code copied from write_common_modules method in monai.deploy.operators.dicom_utils
366+
367+ # Contributing Equipment Sequence
368+ # The Creator shall describe each algorithm that was used to generate the results in the
369+ # Contributing Equipment Sequence (0018,A001). Multiple items may be included. The Creator
370+ # shall encode the following details in the Contributing Equipment Sequence:
371+ # • Purpose of Reference Code Sequence (0040,A170) shall be (Newcode1, 99IHE, 1630 "Processing Algorithm")
372+ # • Manufacturer (0008,0070)
373+ # • Manufacturer’s Model Name (0008,1090)
374+ # • Software Versions (0018,1020)
375+ # • Device UID (0018,1002)
376+
377+ if self .model_info :
378+ # First create the Purpose of Reference Code Sequence
379+ seq_purpose_of_reference_code = PyDicomSequence ()
380+ seg_purpose_of_reference_code = Dataset ()
381+ seg_purpose_of_reference_code .CodeValue = "Newcode1"
382+ seg_purpose_of_reference_code .CodingSchemeDesignator = "99IHE"
383+ seg_purpose_of_reference_code .CodeMeaning = '"Processing Algorithm'
384+ seq_purpose_of_reference_code .append (seg_purpose_of_reference_code )
385+
386+ seq_contributing_equipment = PyDicomSequence ()
387+ seg_contributing_equipment = Dataset ()
388+ seg_contributing_equipment .PurposeOfReferenceCodeSequence = seq_purpose_of_reference_code
389+ # '(121014, DCM, “Device Observer Manufacturer")'
390+ seg_contributing_equipment .Manufacturer = self .model_info .creator
391+ # u'(121015, DCM, “Device Observer Model Name")'
392+ seg_contributing_equipment .ManufacturerModelName = self .model_info .name
393+ # u'(111003, DCM, “Algorithm Version")'
394+ seg_contributing_equipment .SoftwareVersions = self .model_info .version
395+ seg_contributing_equipment .DeviceUID = self .model_info .uid # u'(121012, DCM, “Device Observer UID")'
396+ seq_contributing_equipment .append (seg_contributing_equipment )
397+ seg .ContributingEquipmentSequence = seq_contributing_equipment
398+
359399 seg .save_as (output_path )
360400
361401 try :
0 commit comments