Ejemplo n.º 1
0
 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,
         ])
Ejemplo n.º 2
0
 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)
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
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()
Ejemplo n.º 9
0
 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()
Ejemplo n.º 11
0
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("发送影像成功")
Ejemplo n.º 12
0
 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())
Ejemplo n.º 13
0
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
Ejemplo n.º 14
0
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]
Ejemplo n.º 15
0
 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())
Ejemplo n.º 16
0
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
Ejemplo n.º 17
0
 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'
Ejemplo n.º 18
0
 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
             )
Ejemplo n.º 19
0
 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)
Ejemplo n.º 20
0
 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()
Ejemplo n.º 21
0
 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
Ejemplo n.º 22
0
 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)
Ejemplo n.º 23
0
    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
Ejemplo n.º 24
0
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)
Ejemplo n.º 25
0
    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"))
Ejemplo n.º 26
0
 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)
Ejemplo n.º 28
0
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)
Ejemplo n.º 29
0
Archivo: dos.py Proyecto: pytrip/pytrip
    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)
Ejemplo n.º 30
0
    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)
Ejemplo n.º 31
0
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
Ejemplo n.º 32
0
 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)
Ejemplo n.º 33
0
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
Ejemplo n.º 34
0
    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()
Ejemplo n.º 35
0
 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
Ejemplo n.º 36
0
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
Ejemplo n.º 37
0
    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)
Ejemplo n.º 38
0
 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()
Ejemplo n.º 39
0
    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)
Ejemplo n.º 40
0
 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
Ejemplo n.º 41
0
 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)