def setUp(self): '''Creates a Measurement for a numeric value in millimiter unit with derivation, method and reference to an image region.''' super().setUp() self._value = 10 self._unit = codes.cid7181.SquareMillimeter self._tracking_identifier = TrackingIdentifier( uid=generate_uid(), identifier='prostate zone size measurement') self._derivation = codes.cid7464.Total self._method = codes.cid7473.AreaOfClosedIrregularPolygon self._location = \ codes.cid6300.RightAnteriorMiddlePeripheralZoneOfProstate self._finding_site = FindingSite(anatomic_location=self._location) self._image = SourceImageForRegion( referenced_sop_class_uid='1.2.840.10008.5.1.4.1.1.2.2', referenced_sop_instance_uid=generate_uid()) self._region = ImageRegion(graphic_type=GraphicTypeValues.POINT, graphic_data=np.array([[1.0, 1.0]]), source_image=self._image) self._name = codes.cid7469.Area self._measurement = Measurement( name=self._name, value=self._value, unit=self._unit, tracking_identifier=self._tracking_identifier, method=self._method, derivation=self._derivation, finding_sites=[ self._finding_site, ])
def setUp(self): super().setUp() self._ref_dataset = Dataset() self._ref_dataset.PatientID = '1' self._ref_dataset.PatientName = 'patient' self._ref_dataset.PatientBirthDate = '2000101' self._ref_dataset.PatientSex = 'o' self._ref_dataset.SOPClassUID = '1.2.840.10008.5.1.4.1.1.2.2' self._ref_dataset.SOPInstanceUID = generate_uid() self._ref_dataset.SeriesInstanceUID = generate_uid() self._ref_dataset.StudyInstanceUID = generate_uid() self._ref_dataset.AccessionNumber = '2' self._ref_dataset.StudyID = '3' self._ref_dataset.StudyDate = datetime.now().date() self._ref_dataset.StudyTime = datetime.now().time() self._ref_dataset.ReferringPhysicianName = 'doctor' self._content = Dataset() self._series_instance_uid = generate_uid() self._series_number = 3 self._sop_instance_uid = generate_uid() self._instance_number = 4 self._institution_name = 'institute' self._institutional_department_name = 'department' self._manufacturer = 'manufacturer' self._report = Comprehensive3DSR( evidence=[self._ref_dataset], content=self._content, series_instance_uid=self._series_instance_uid, series_number=self._series_number, sop_instance_uid=self._sop_instance_uid, instance_number=self._instance_number, institution_name=self._institution_name, institutional_department_name=self._institutional_department_name, manufacturer=self._manufacturer)
def ConvertByHighDicomNew(single_frame_folder_or_list, OutputPrefix) -> list: all_datasets = GetFrameSetsFromFiles(single_frame_folder_or_list) framesets = _FrameSetCollection(all_datasets).frame_sets multi_frame_study_instance_uid = all_datasets[0].StudyInstanceUID parent_child_uids = [] multi_frame_series_instance_uid = generate_uid() mf_dir = os.path.join(OutputPrefix, '{}'.format( multi_frame_series_instance_uid)) for n, frameset in enumerate(framesets, 1): ref_ds = frameset.frames[0] sop_class_uid = frameset.get_sop_class_uid() if sop_class_uid not in supported_sop_class_uids: continue # try: multi_frame_sop_instance_uid = generate_uid() mf_prefix = os.path.join(mf_dir, '{}.dcm'.format( multi_frame_sop_instance_uid)) if not os.path.exists(mf_dir): os.makedirs(mf_dir) pr_ch = ConvertFrameset( frameset, mf_prefix, multi_frame_study_instance_uid, multi_frame_series_instance_uid) parent_child_uids.append(pr_ch) return parent_child_uids
def test_generate_uid(self): """Test UID generator""" # Test standard UID generation with pydicom prefix uid = generate_uid() assert uid[:26] == PYDICOM_ROOT_UID assert len(uid) <= 64 # Test standard UID generation with no prefix uid = generate_uid(None) assert uid[:5] == '2.25.' assert len(uid) <= 64 # Test invalid UID prefixes for invalid_prefix in (('1' * 63) + '.', '', '.', '1', '1.2', '1.2..3.', '1.a.2.', '1.01.1.'): with pytest.raises(ValueError): generate_uid(prefix=invalid_prefix) # Test some valid prefixes and make sure they survive for valid_prefix in ('0.', '1.', '1.23.', '1.0.23.', ('1' * 62) + '.', '1.2.3.444444.'): uid = generate_uid(prefix=valid_prefix) assert uid[:len(valid_prefix)] == valid_prefix assert len(uid) <= 64
def test_generate_uid(self): """Test UID generator""" # Test standard UID generation with pydicom prefix uid = generate_uid() assert uid[:26] == PYDICOM_ROOT_UID assert len(uid) <= 64 # Test standard UID generation with no prefix uid = generate_uid(None) assert uid[:5] == '2.25.' assert len(uid) <= 64 # Test invalid UID prefixes for invalid_prefix in (('1' * 63) + '.', '', '.', '1', '1.2', '1.2..3.', '1.a.2.', '1.01.1.'): with pytest.raises(ValueError): generate_uid(prefix=invalid_prefix) # Test some valid prefixes and make sure they survive for valid_prefix in ('0.', '1.', '1.23.', '1.0.23.', ('1' * 62) + '.', '1.2.3.444444.'): uid = generate_uid(prefix=valid_prefix) assert uid[:len(valid_prefix)] == valid_prefix assert len(uid) <= 64
def create_empty_cube(self, value, dimx, dimy, dimz, pixel_size, slice_distance, slice_offset=0.0): """ Creates an empty Cube object. Values are stored as 2-byte integers. :param int16 value: integer value which will be assigned to all voxels. :param int dimx: number of voxels along x :param int dimy: number of voxels along y :param int dimz: number of voxels along z :param float pixel_size: size of each pixel (x == y) in [mm] :param float slice_distance: the distance between two slices (z) in [mm] :param float slice_offset: start position of the first slice in [mm] (default 0.0 mm) """ self.dimx = dimx self.dimy = dimy self.dimz = dimz self.slice_number = dimz self.pixel_size = pixel_size self.slice_distance = slice_distance self.slice_thickness = slice_distance # use distance for thickness as default self.cube = np.ones((dimz, dimy, dimx), dtype=np.int16) * value self.slice_dimension = dimx self.num_bytes = 2 self.data_type = "integer" self.pydata_type = np.int16 self.slice_pos = [slice_distance * i + slice_offset for i in range(dimz)] self.header_set = True self.patient_id = '' # UIDs unique for whole structure set # generation of UID is done here in init, the reason why we are not generating them in create_dicom # method is that subsequent calls to write method shouldn't changed UIDs self._dicom_study_instance_uid = uid.generate_uid(prefix=None) self._ct_dicom_series_instance_uid = uid.generate_uid(prefix=None) # unique for each CT slice self._ct_sop_instance_uid = uid.generate_uid(prefix=None)
def testGenerateUID(self): ''' Test UID generator ''' # Test standard UID generation with pydicom prefix uid = generate_uid() self.assertEqual(uid[:26], pydicom_root_UID) self.assertTrue(len(uid) <= 64) # Test standard UID generation with no prefix uid = generate_uid(None) self.assertEqual(uid[:5], '2.25.') self.assertTrue(len(uid) <= 64) # Test invalid UID prefixes for invalid_prefix in (('1' * 63) + '.', '', '.', '1', '1.2', '1.2..3.', '1.a.2.', '1.01.1.'): self.assertRaises(ValueError, lambda: generate_uid(prefix=invalid_prefix)) # Test some valid prefixes and make sure they survive for valid_prefix in ('0.', '1.', '1.23.', '1.0.23.', ('1' * 62) + '.', '1.2.3.444444.'): uid = generate_uid(prefix=valid_prefix) self.assertEqual(uid[:len(valid_prefix)], valid_prefix) self.assertTrue(len(uid) <= 64)
def save3dDicom(volume, info, path, newSeriesNumber=None, newSeriesDescription=None, newImageComment=None, startImageNumber=1): try: os.mkdir(path) except: pass if newSeriesNumber is None: newSeriesNumber = info[0].SeriesNumber newSeriesUID = info[0].SeriesInstanceUID else: newSeriesUID = UID.generate_uid() if newSeriesDescription is None: newSeriesDescription = info[0].SeriesDescription if len(info) == 1: dataArray = volume[:, :, 0] dicomFileData = copy.deepcopy(info[0]) # create a copy of object if dataArray.dtype == 'uint16': # check correct format dicomFileData.PixelData = dataArray.tostring() else: dicomFileData.PixelData = dataArray.round().astype( 'uint16').tostring() dicomFileData.SeriesNumber = newSeriesNumber dicomFileData.SeriesInstanceUID = newSeriesUID dicomFileData.SOPInstanceUID = UID.generate_uid() if newImageComment is not None: dicomFileData.ImageComment = newImageComment fName = os.path.join( path, "image0001.dcm") # if one wants to save a part of a dataset dicom.write_file(fName, dicomFileData) else: bar = Bar('Saving Dicom', max=len(info)) for sl in range(len(info)): dataArray = volume[..., sl] dicomFileData = copy.deepcopy(info[sl]) # create a copy of object if dataArray.dtype == 'uint16': # check correct format dicomFileData.PixelData = dataArray.tostring() else: dicomFileData.PixelData = dataArray.round().astype( 'uint16').tostring() dicomFileData.SeriesNumber = newSeriesNumber dicomFileData.SeriesInstanceUID = newSeriesUID dicomFileData.SOPInstanceUID = UID.generate_uid() if newImageComment is not None: dicomFileData.ImageComment = newImageComment fName = os.path.join( path, "image%04d.dcm" % (sl + startImageNumber)) # if one wants to save a part of a dataset dicom.write_file(fName, dicomFileData) bar.next() bar.finish()
def setUp(self): super().setUp() self._observer_person_context = ObserverContext( observer_type=codes.cid270.Person, observer_identifying_attributes=PersonObserverIdentifyingAttributes( name='Foo Bar')) self._observer_device_context = ObserverContext( observer_type=codes.cid270.Device, observer_identifying_attributes=DeviceObserverIdentifyingAttributes( uid=generate_uid())) self._observation_context = ObservationContext( observer_person_context=self._observer_person_context, observer_device_context=self._observer_device_context) self._procedure_reported = codes.cid100.CTPerfusionHeadWithContrastIV self._tracking_identifier = TrackingIdentifier( uid=generate_uid(), identifier='planar roi measurements') self._image = SourceImageForRegion( referenced_sop_class_uid='1.2.840.10008.5.1.4.1.1.2.2', referenced_sop_instance_uid=generate_uid()) self._region = ImageRegion(graphic_type=GraphicTypeValues.CIRCLE, graphic_data=np.array([[1.0, 1.0], [2.0, 2.0]]), source_image=self._image) self._measurements = PlanarROIMeasurementsAndQualitativeEvaluations( tracking_identifier=self._tracking_identifier, referenced_region=self._region) self._measurement_report = MeasurementReport( observation_context=self._observation_context, procedure_reported=self._procedure_reported, imaging_measurements=[self._measurements])
def split_volume_to_dcms(volume, template_dcms): # Verify shape if len(template_dcms) != volume.shape[0]: raise Exception("Number of template DCMS don't equal number of slices of 3d volume ") # Sort the template dcms to match the volume Slice Location ##TODO: Not mentioned but from the wording it appears that slice location doesnt have to be respected #template_dcms = sorted(template_dcms, key=lambda dcm: float(dcm.SliceLocation)) # Generate UIDs series_iud = generate_uid() # Copy back the pixel data for i, dcm in enumerate(template_dcms): a_slice = volume[i].squeeze() # Establish Scale range and normalize to 0 and 1 type_info = np.iinfo(dcm.pixel_array.dtype) a_slice = (a_slice - np.min(a_slice))/np.ptp(a_slice) # Prevent over/underflow, a_slice = a_slice.astype(np.float64) a_slice = a_slice * (type_info.max - type_info.min) + type_info.min a_slice = a_slice.astype(dcm.pixel_array.dtype) # Update Template dcm.PixelData = a_slice.tobytes() dcm.SeriesInstanceUID = series_iud dcm.SOPInstanceUID = generate_uid()
def send_image(): images = find_images(Path) studyUID = generate_uid() seriesUID = generate_uid() reg_info = get_reginfo() for i in images: image_file = os.path.join(Path, i) store_image(image_file, studyUID, seriesUID, **reg_info) print("发送影像成功")
def setUp(self): super().setUp() self._sop_class_uid = '1.2.840.10008.5.1.4.1.1.66.4' self._sop_instance_uid = generate_uid() self._segment_number = 1 self._frame_number = 1 self._source_image = SourceImageForSegmentation( referenced_sop_class_uid='1.2.840.10008.5.1.4.1.1.2.2', referenced_sop_instance_uid=generate_uid())
def numpy_to_dicom(pixel_data, dcm_template): series_instance_uid = generate_uid() sop_instance_uid = generate_uid() data_type = dcm_template[0].pixel_array.dtype for i in range(pixel_data.shape[-1]): dcm_template[i].PixelData = pixel_data[:, :, i].astype(data_type) dcm_template[i].SeriesInstanceUID = series_instance_uid dcm_template[i].SOPInstanceUID = sop_instance_uid return dcm_template
def update_referenced_uids(ds, instance_uids_map): for item in ds.get('SourceImageSequence', list()): ref_sop_instance_uid = item.ReferencedSOPInstanceUID if ref_sop_instance_uid not in instance_uids_map: instance_uids_map[ref_sop_instance_uid] = generate_uid() item.ReferencedSOPInstanceUID = instance_uids_map[ref_sop_instance_uid] for item in ds.get('ReferencedImageSequence', list()): ref_sop_instance_uid = item.ReferencedSOPInstanceUID if ref_sop_instance_uid not in instance_uids_map: instance_uids_map[ref_sop_instance_uid] = generate_uid() item.ReferencedSOPInstanceUID = instance_uids_map[ref_sop_instance_uid]
def setUp(self): super().setUp() self._sop_class_uid = '1.2.840.10008.5.1.4.1.1.66.4' self._sop_instance_uid = generate_uid() self._segment_number = 1 self._frame_numbers = [ 1, 2, ] self._source_series = SourceSeriesForSegmentation( referenced_series_instance_uid=generate_uid())
def test_ds(): ds = pydicom.Dataset() ds.PatientName = 'Test^Test^Test' ds.PatientSex = 'M' ds.PatientID = 'auto1' ds.SpecificCharacterSet = 'ISO_IR 192' ds.StudyInstanceUID = uid.generate_uid() ds.SeriesInstanceUID = uid.generate_uid() ds.SOPInstanceUID = uid.generate_uid() ds.SOPClassUID = uids.BASIC_TEXT_SR_STORAGE return ds
def setUp(self): super().setUp() self._modalities = ('CT', 'MR', 'PET') self._ref_dataset_seq_CT = \ self.generate_common_dicom_dataset_series(3, Modality.CT) self._ref_dataset_seq_MR = \ self.generate_common_dicom_dataset_series(3, Modality.MR) self._ref_dataset_seq_PET = \ self.generate_common_dicom_dataset_series(3, Modality.PT) self._output_series_instance_uid = generate_uid() self._output_sop_instance_uid = generate_uid() self._output_series_number = '1' self._output_instance_number = '1'
def update_uids_cb(ds: Dataset, elem: DataElement) -> None: """Callback for updating UID values except `SOPClassUID`""" if elem.VR == "UI" and elem.keyword != "SOPClassUID": if elem.VM > 1: elem.value = [ generate_uid(uid_prefix, [x] + add_uid_entropy) # type: ignore for x in elem.value ] else: elem.value = generate_uid( uid_prefix, [elem.value] + add_uid_entropy # type: ignore )
def setUp(self): super().setUp() self._tracking_identifier = TrackingIdentifier( uid=generate_uid(), identifier='planar roi measurements') self._image = SourceImageForRegion( referenced_sop_class_uid='1.2.840.10008.5.1.4.1.1.2.2', referenced_sop_instance_uid=generate_uid()) self._region = ImageRegion(graphic_type=GraphicTypeValues.CIRCLE, graphic_data=np.array([[1.0, 1.0], [2.0, 2.0]]), source_image=self._image) self._measurements = PlanarROIMeasurementsAndQualitativeEvaluations( tracking_identifier=self._tracking_identifier, referenced_region=self._region)
def setUp(self): super().setUp() self._rgb_pixel_array = np.zeros((10, 10, 3), dtype=np.uint8) self._monochrome_pixel_array = np.zeros((10, 10), dtype=np.uint16) self._study_instance_uid = generate_uid() self._series_instance_uid = generate_uid() self._sop_instance_uid = generate_uid() self._series_number = int(np.random.choice(100)) self._instance_number = int(np.random.choice(100)) self._manufacturer = 'ABC' self._laterality = 'L' self._patient_orientation = ['A', 'R'] self._container_identifier = str(np.random.choice(100)) self._specimen_identifier = str(np.random.choice(100)) self._specimen_uid = generate_uid()
def test_entropy_src_custom(self): """Test UID generator with custom entropy sources""" # Should be identical uid = generate_uid(entropy_srcs=['lorem', 'ipsum']) rf = '1.2.826.0.1.3680043.8.498.87507166259346337659265156363895084463' assert uid == rf assert len(uid) == 64
def __init__(self, sequence_data): """Object initialization Parameters ---------- sequence_data : List of items with data to generate each sequence item, in the format of a list with a dictionary for each item, which in turn can contain a sequence, e.g. list of dictionaries """ super().__init__() for sequence_item in sequence_data: # Initiate dataset ds = Dataset() # Set required DICOM attributes ds.SeriesInstanceUID = generate_uid() ds.ReferencedSOPSequence = generate_sequence( "ReferencedSOPSequence", dict()) # Update and insert additional DICOM attributes as available ds = update_and_insert_additional_DICOM_attributes_in_ds( ds, sequence_item) # Remove mutually exclusive elemenets if "ReferencedSOPSequence" in sequence_item and "ReferencedImageSequence" in ds: del ds.ReferencedImageSequence elif "ReferencedImageSequence" in sequence_item and "ReferencedSOPSequence" in ds: del ds.ReferencedSOPSequence self.sequence.append(ds)
def get_clean_worklist(self): """ Generates a clean worklist """ worklist_item = Dataset() worklist_item.StudyInstanceUID = generate_uid(prefix='1.2.840.113619.2.391.6789.', entropy_srcs=[_create_random_ascii_string(10), _create_random_ascii_string(10)]) worklist_item.Modality = 'US' worklist_item.SpecificCharacterSet = self._specific_charset worklist_item.AccessionNumber = '123' worklist_item.PatientBirthDate = '19901015' worklist_item.PatientName = 'Clean^Exam' worklist_item.PatientID = _create_random_ascii_string(64) worklist_item.IssuerOfPatientID = 'Issuer of patient id: Bob' worklist_item.PatientWeight = str(100.0) worklist_item.PatientSize = str(2.1) worklist_item.AdmissionID = 'Admission id 3' worklist_item.RequestedProcedureID = 'Step id 2' worklist_item.RequestedProcedureDescription = 'Step description Clean Exam' otherPatientIdsSq = [Dataset(), Dataset()] for otherPatientId in otherPatientIdsSq: otherPatientId.PatientID = 'Bob123' otherPatientId.IssuerOfPatientID = 'Issuer of patient id: Arne' otherPatientId.TypeOfPatientID = 'TEXT' worklist_item.OtherPatientIDsSequence = otherPatientIdsSq step = Dataset() step.ScheduledPerformingPhysicianName = 'Ola Nordmann' step.ScheduledProcedureStepStartDate = '20201224' step.ScheduledProcedureStepStartTime = '121212' step.ScheduledProcedureStepDescription = 'Scheduled procedure step description ' step.CommentsOnTheScheduledProcedureStep = 'Scheduled step comments ' worklist_item.ScheduledProcedureStepSequence = [step] return worklist_item
def frameset_for_one_series(single_frame_file_path: List[str], series_folder_prifix: str, single_frame_series_uid: str): logger = logging.getLogger(__name__) # All frames set created out of one series must have the same series # instance uid. So I have to create on series instance uid and a # destination folder for future multiframe images # ------------------------------------------------ multi_frame_series_uid = generate_uid( prefix="1.3.6.1.4.1.43046.3" + ".1.9.", entropy_srcs=[single_frame_series_uid]) multi_frame_series_folder = os.path.join(series_folder_prifix, multi_frame_series_uid) if not os.path.exists(multi_frame_series_folder): os.makedirs(multi_frame_series_folder) ds_list = [] for f_bl in single_frame_file_path: ds_list.append(pydicom.read_file(f_bl)) try: fs_collection = _FrameSetCollection(ds_list) fs = fs_collection.frame_sets except BaseException as err: msg = str(err) msg += '\n The first sample out of {}:\n{}'.format( len(single_frame_file_path), str(single_frame_file_path[0])) logger.error(msg, exc_info=True) fs = [] return (fs, multi_frame_series_uid, multi_frame_series_folder)
def update_dicom_tags(self): """Update DICOM UIDs, Content Date/Time, and Dose Comment""" # Store the source SOPClassUID and SOPInstanceUID seq_data = { "ReferencedSOPClassUID": self.sop_class_uid, "ReferencedSOPInstanceUID": self.sop_instance_uid, } add_dicom_sequence(self.ds, "ReferencedInstanceSequence", seq_data) if self.other_sop_class_uid is not None: seq_data = { "ReferencedSOPClassUID": self.other_sop_class_uid, "ReferencedSOPInstanceUID": self.other_sop_instance_uid, } add_dicom_sequence(self.ds, "ReferencedInstanceSequence", seq_data) # Create a new SOPInstanceUID set_dicom_tag_value( self.ds, "SOPInstanceUID", generate_uid(prefix=dicompyler_uid_prefix_rtdose), ) # Store the dose summation type in the DoseComment tag if self.summation_type: set_dicom_tag_value(self.ds, "DoseComment", "%s SUMMATION" % self.summation_type) # Update the Date and Time tags now = datetime.now() set_dicom_tag_value(self.ds, "ContentDate", now.strftime("%Y%m%d")) set_dicom_tag_value(self.ds, "ContentTime", now.strftime("%H%M%S"))
def test_entropy_src_custom(self): """Test UID generator with custom entropy sources""" # Should be identical uid = generate_uid(entropy_srcs=['lorem', 'ipsum']) rf = '1.2.826.0.1.3680043.8.498.87507166259346337659265156363895084463' assert uid == rf assert len(uid) == 64
def add_landmark(self, dcm_file, graphic_data, finding, finding_site, tracking_id=None, tracking_uid=None, qualitative_evaluations=None, coded_values=None, text_values=None): """Add landmark value Arguments: dcm_file {[type]} -- [description] graphic_data {[type]} -- [description] finding {[type]} -- [description] finding_site {[type]} -- [description] Keyword Arguments: tracking_id {[type]} -- [description] (default: {None}) tracking_uid {[type]} -- [description] (default: {None}) """ if not tracking_id: tracking_id = ''.join(random.choice('0123456789ABCDEF') for i in range(16)) if not tracking_uid: tracking_uid = uid.generate_uid() ds_ref = read_file(dcm_file) ds = self.initiate_measurement_group() ds.ContentSequence = self.initiate_content_sequence(tracking_id, tracking_uid, finding, finding_site) if coded_values is not None: ds = self.add_coded_values(ds, coded_values) ds.ContentSequence.append(update_and_insert_additional_DICOM_attributes_in_ds(Dataset(), { "RelationshipType": "CONTAINS", "ValueType": "CODE", "ConceptNameCodeSequence": [{ "CodeValue": "758637006", "CodingSchemeDesignator": "SCT", "CodeMeaning": "Anatomical locations"}], "ConceptCodeSequence": [{ "CodeValue": "26216008", "CodingSchemeDesignator": "SCT", "CodeMeaning": "Center"}], "ContentSequence": [{ "RelationshipType": "INFERRED FROM", "ValueType": "SCOORD", "ContentSequence": [{ "ReferencedSOPSequence": [{ "ReferencedSOPClassUID": ds_ref.SOPClassUID, "ReferencedSOPInstanceUID": ds_ref.SOPInstanceUID }], "RelationshipType": "SELECTED FROM", "ValueType": "IMAGE" # value type }], "GraphicData": graphic_data, "GraphicType": "POINT", }] })) if text_values is not None: ds = self.add_text_values(ds, text_values) if qualitative_evaluations is not None: ds = self.add_qualitative_evaluations(ds, qualitative_evaluations) self.dataset.ContentSequence[3].ContentSequence.append(ds)
def add_refd_frame_of_ref_sequence(ds: FileDataset, series_data): refd_frame_of_ref = Dataset() refd_frame_of_ref.FrameOfReferenceUID = generate_uid() # TODO Find out if random generation is ok refd_frame_of_ref.RTReferencedStudySequence = create_frame_of_ref_study_sequence(series_data) # Add to sequence ds.ReferencedFrameOfReferenceSequence = Sequence() ds.ReferencedFrameOfReferenceSequence.append(refd_frame_of_ref)
def __init__(self, cube=None): """ Creates a DosCube instance. If cube is provided, then UIDs are inherited from cube. """ super(DosCube, self).__init__(cube) self.type = "DOS" self.target_dose = 0.0 # Target dose in Gy or Gy(RBE) # UIDs unique for whole structure set # generation of UID is done here in init, the reason why we are not generating them in create_dicom # method is that subsequent calls to write method shouldn't changed UIDs if cube is not None: self._dicom_study_instance_uid = cube._dicom_study_instance_uid else: self._dicom_study_instance_uid = uid.generate_uid(prefix=None) self._plan_dicom_series_instance_uid = uid.generate_uid(prefix=None) self._dose_dicom_series_instance_uid = uid.generate_uid(prefix=None)
def __init__(self, cube=None): """ Creates a DosCube instance. If cube is provided, then UIDs are inherited from cube. """ super(DosCube, self).__init__(cube) self.type = "DOS" self.target_dose = 0.0 # Target dose in Gy or Gy(RBE) # UIDs unique for whole structure set # generation of UID is done here in init, the reason why we are not generating them in create_dicom # method is that subsequent calls to write method shouldn't changed UIDs if cube is not None: self._dicom_study_instance_uid = cube._dicom_study_instance_uid else: self._dicom_study_instance_uid = uid.generate_uid(prefix=None) self._plan_dicom_series_instance_uid = uid.generate_uid(prefix=None) self._dose_dicom_series_instance_uid = uid.generate_uid(prefix=None)
def get_file_meta() -> FileMetaDataset: file_meta = FileMetaDataset() file_meta.FileMetaInformationGroupLength = 202 file_meta.FileMetaInformationVersion = b'\x00\x01' file_meta.TransferSyntaxUID = ImplicitVRLittleEndian file_meta.MediaStorageSOPClassUID = SOPClassUID.RTSTRUCT file_meta.MediaStorageSOPInstanceUID = generate_uid() # TODO find out random generation is fine file_meta.ImplementationClassUID = SOPClassUID.RTSTRUCT_IMPLEMENTATION_CLASS return file_meta
def setUp(self): super().setUp() self._tracking_identifier = TrackingIdentifier( uid=generate_uid(), identifier='volumetric roi measurements') self._images = [ SourceImageForRegion( referenced_sop_class_uid='1.2.840.10008.5.1.4.1.1.2.2', referenced_sop_instance_uid=generate_uid()) for i in range(3) ] self._regions = [ ImageRegion(graphic_type=GraphicTypeValues.POLYLINE, graphic_data=np.array([[1.0, 1.0], [2.0, 2.0], [3.0, 3.0], [1.0, 1.0]]), source_image=self._images[i]) for i in range(3) ] self._measurements = VolumetricROIMeasurementsAndQualitativeEvaluations( tracking_identifier=self._tracking_identifier, referenced_regions=self._regions)
def _basic_file_meta(class_UID): """Create basic file meta for DICOM dataset.""" # File meta info data elements file_meta = FileMetaDataset() file_meta.FileMetaInformationVersion = b'\x00\x01' file_meta.MediaStorageSOPClassUID = class_UID file_meta.MediaStorageSOPInstanceUID = generate_uid() file_meta.TransferSyntaxUID = '1.2.840.10008.1.2' return file_meta
def __init__(self, ct_path, mask, structures=None, output=None): if structures is None: structures = [] self.ct_path = ct_path self.mask = mask self.structures = structures self.output = output or "RS.dcm" self.ct_files = natsorted([os.path.join(self.ct_path, ct) for ct in os.listdir(self.ct_path) if ct.endswith("dcm")]) self.ds_cts = [dcmread(ct_file) for ct_file in self.ct_files] self.ds_ct_sop_instance_uid = [ds_ct.SOPInstanceUID for ds_ct in self.ds_cts] self.ds_ct_reference = self.ds_cts[0] self.mask = Mask(self.mask, ds_cts=self.ds_cts, ct_path=self.ct_path) self.ds_rs = Dataset() # RS meta self.ds_rs.file_meta = FileMetaDataset() self.ds_rs.file_meta.MediaStorageSOPClassUID = 'RT Structure Set Storage' self.ds_rs.file_meta.MediaStorageSOPInstanceUID = '1.2.345.678.9.1.11111111111111111.1111.11111' # RS transfer syntax self.ds_rs.is_little_endian = True self.ds_rs.is_implicit_VR = True # RS creation date/time date_time = datetime.datetime.now() self.ds_rs.ContentDate = date_time.strftime('%Y%m%d') time_str = date_time.strftime('%H%M%S') self.ds_rs.ContentTime = time_str # RS common tags for tag in COMMON_TAGS: if tag in self.ds_ct_reference: self.ds_rs[tag] = self.ds_ct_reference[tag] # RS series self.ds_rs.Modality = 'RTSTRUCT' self.ds_rs.SOPClassUID = UID('1.2.840.10008.5.1.4.1.1.481.3') self.ds_rs.SOPInstanceUID = generate_uid() self.ds_rs.ManufacturerModelName = "segmentation_RT" self.ds_rs.StructureSetLabel = 'RS: Unapproved' self.ds_rs.ApprovalStatus = 'UNAPPROVED' # RS empty sequences self.ds_rs.add_new('RTROIObservationsSequence', 'SQ', Sequence()) self.ds_rs.add_new('StructureSetROISequence', 'SQ', Sequence()) self.ds_rs.add_new('ROIContourSequence', 'SQ', Sequence()) self.ds_rs.add_new('ReferencedFrameOfReferenceSequence', 'SQ', Sequence()) # RS referenced frame of reference sequence self.add_referenced_frame_of_reference_sequence()
def test_none(self): """Test generate_uid(None).""" uid = generate_uid(prefix=None) # Check prefix assert '2.25.' == uid[:5] # Check UUID suffix as_uuid = uuid.UUID(int=int(uid[5:])) assert isinstance(as_uuid, uuid.UUID) assert as_uuid.version == 4 assert as_uuid.variant == uuid.RFC_4122
def _create_temporary_dataset(shape=(100, 1024, 1024, 3), bit_depth=16): """Function to create a temporary dataset for use in testing. Parameters ---------- shape : 4-tuple The (frames, rows, columns, channels) of the test dataset. bit_depth : int The BitsAllocated value to use for the dataset, one of 8, 16, 32, 64. Returns ------- tempfile.TemporaryFile A created DICOM File Format conformant dataset. """ ds = Dataset() ds.is_little_endian = True ds.is_implicit_VR = False ds.file_meta = Dataset() ds.file_meta.TransferSyntaxUID = ExplicitVRLittleEndian ds.SOPClassUID = '1.2.3.4' ds.SOPInstanceUID = generate_uid() ds.BitsAllocated = bit_depth ds.PixelRepresentation = 0 ds.PlanarConfiguration = 0 ds.Rows = shape[1] ds.Columns = shape[2] ds.NumberOfFrames = shape[0] ds.SamplesPerPixel = shape[3] if shape[3] == 1: ds.PhotometricInterpretation = 'MONOCHROME2' elif shape[3] == 3: ds.PhotometricInterpretation = 'RGB' arr = np.zeros(shape, dtype='uint{}'.format(bit_depth)) ds.PixelData = arr.tobytes() if len(ds.PixelData) % 2: ds.PixelData += b'\x00' tfile = TemporaryFile(mode='w+b') ds.save_as(tfile, write_like_original=False) tfile.seek(0) return tfile
def test_commitment_failure(self): uids = [(sc.COMPREHENSIVE_SR_STORAGE, uid.generate_uid()+str(i)) for i in range(10)] ae1 = CommitmentAE(self, self.transaction, uids[:5], uids[5:], self.event, self.remote_ae1, 'AET2', 11113)\ .add_scp(sc.StorageCommitment())\ .add_scu(sc.storage_commitment_scu) ae2 = CommitmentAE(self, self.transaction, uids[:5], uids[5:], self.event, self.remote_ae2, 'AET2', 11112)\ .add_scp(sc.StorageCommitment()) with ae2: with ae1: with ae1.request_association(self.remote_ae2) as assoc: service = assoc.get_scu(sc.STORAGE_COMMITMENT_SOP_CLASS) status = service(self.transaction, uids, 1) self.assertEqual(status, statuses.SUCCESS) self.event.wait(20)
def setUp(self): self.event = threading.Event() self.remote_ae1 = dict(address='127.0.0.1', port=11113, aet='AET1') self.remote_ae2 = dict(address='127.0.0.1', port=11112, aet='AET2') self.transaction = uid.generate_uid()
def __init__(self, cube=None): if cube is not None: # copying constructor self.header_set = cube.header_set self.version = cube.version self.modality = cube.modality self.created_by = cube.created_by self.creation_info = cube.creation_info self.primary_view = cube.primary_view self.data_type = cube.data_type self.num_bytes = cube.num_bytes self.byte_order = cube.byte_order self.patient_name = cube.patient_name self.patient_id = cube.patient_id self.slice_dimension = cube.slice_dimension self.pixel_size = cube.pixel_size self.slice_distance = cube.slice_distance self.slice_thickness = cube.slice_thickness self.slice_number = cube.slice_number self.xoffset = cube.xoffset # self.xoffset are in mm, synced with DICOM contours self.dimx = cube.dimx self.yoffset = cube.yoffset # self.yoffset are in mm, synced with DICOM contours self.dimy = cube.dimy self.zoffset = cube.zoffset # self.zoffset are in mm, synced with DICOM contours self.dimz = cube.dimz self.z_table = cube.z_table self.slice_pos = cube.slice_pos self.basename = cube.basename self._set_format_str() self._set_number_of_bytes() # unique for whole structure set self._dicom_study_instance_uid = cube._dicom_study_instance_uid self._ct_dicom_series_instance_uid = cube._ct_dicom_series_instance_uid # unique for each CT slice self._ct_sop_instance_uid = cube._ct_sop_instance_uid self.cube = np.zeros((self.dimz, self.dimy, self.dimx), dtype=cube.pydata_type) else: import getpass from pytrip import __version__ as _ptversion self.header_set = False self.version = "2.0" self.modality = "CT" self.created_by = getpass.getuser() self.creation_info = "Created with PyTRiP98 {:s}".format(_ptversion) self.primary_view = "transversal" # e.g. transversal self.data_type = "" self.num_bytes = "" self.byte_order = "vms" # aix or vms self.patient_name = "" self.patient_id = datetime.datetime.today().strftime('%Y%m%d-%H%M%S') # create a new patient ID if absent self.slice_dimension = "" # eg. 256 meaning 256x256 pixels. self.pixel_size = "" # size in [mm] self.slice_distance = "" # distance between slices in [mm] self.slice_thickness = "" # thickness of slice (usually equal to slice_distance) in [mm] self.slice_number = "" # number of slices in file. self.xoffset = 0.0 self.dimx = "" # number of pixels along x (e.g. 256) self.yoffset = 0.0 self.dimy = "" self.zoffset = 0.0 self.dimz = "" self.slice_pos = [] self.basename = "" # UIDs unique for whole structure set # generation of UID is done here in init, the reason why we are not generating them in create_dicom # method is that subsequent calls to write method shouldn't changed UIDs self._dicom_study_instance_uid = uid.generate_uid(prefix=None) self._ct_dicom_series_instance_uid = uid.generate_uid(prefix=None) # unique for each CT slice self._ct_sop_instance_uid = uid.generate_uid(prefix=None) self.z_table = False # positions are stored in self.slice_pos (list of slice#,pos(mm),thickness(mm),tilt)
def test_none_iterate(self): """Test generate_uid(None) generates valid UIDs.""" # Generate random UIDs, if a bad method then should eventually fail for ii in range(100000): uid = generate_uid(None) assert uid.is_valid
def test_entropy_src(self): """Test UID generator with default entropy sources""" # Should be different uid = generate_uid(entropy_srcs=None) assert uid != generate_uid(entropy_srcs=None)