예제 #1
0
파일: test_get_scu.py 프로젝트: top501/odil
    def test_both_callbacks(self):
        data_sets = []
        messages = []

        def store_callback(data_set):
            data_sets.append(data_set)

        def get_callback(message):
            messages.append(message)

        get = odil.GetSCU(self.association)
        get.set_affected_sop_class(
            odil.registry.PatientRootQueryRetrieveInformationModelGET)
        get.get(self.query, store_callback, get_callback)

        self.assertEqual(len(data_sets), 1)
        self.assertSequenceEqual(
            data_sets[0].as_string("SOPInstanceUID"),
            [b"2.25.95090344942250266709587559073467305647"])

        self.assertEqual(len(messages), 2)

        self.assertEqual(messages[0].get_number_of_remaining_sub_operations(),
                         0)
        self.assertEqual(messages[0].get_number_of_completed_sub_operations(),
                         1)
        self.assertEqual(messages[0].get_number_of_failed_sub_operations(), 0)
        self.assertEqual(messages[0].get_number_of_warning_sub_operations(), 0)

        self.assertFalse(messages[1].has_number_of_remaining_sub_operations())
        self.assertEqual(messages[1].has_number_of_completed_sub_operations(),
                         1)
        self.assertEqual(messages[1].get_number_of_failed_sub_operations(), 0)
        self.assertEqual(messages[1].get_number_of_warning_sub_operations(), 0)
예제 #2
0
    def test_without_callback(self):
        get = odil.GetSCU(self.association)
        get.set_affected_sop_class(odil.registry.PatientRootQueryRetrieveInformationModelGet)
        data_sets = get.get(self.query)

        self.assertEqual(len(data_sets), 1)
        self.assertSequenceEqual(
            data_sets[0].as_string("SOPInstanceUID"),
            [b"2.25.95090344942250266709587559073467305647"])
예제 #3
0
    def test_only_store_callback(self):
        data_sets = []

        def store_callback(data_set):
            data_sets.append(data_set)

        get = odil.GetSCU(self.association)
        get.set_affected_sop_class(
            odil.registry.PatientRootQueryRetrieveInformationModelGET)
        get.get(self.query, store_callback)

        self.assertEqual(len(data_sets), 1)
        self.assertSequenceEqual(
            data_sets[0].as_string("SOPInstanceUID"),
            ["2.25.95090344942250266709587559073467305647"])
예제 #4
0
def get(host, port, calling_ae_title, called_ae_title, level, keys, directory,
        iso_9660, layout, dicomdir, patient_key, study_key, series_key,
        image_key):

    if dicomdir and not iso_9660:
        raise Exception("Cannot create a DICOMDIR without ISO-9660 filenames")

    query = odil.DataSet()
    for key in keys:
        key, value = key.split("=", 1)
        value = value.split("\\")

        tag = getattr(odil.registry, key)

        vr = odil.registry.public_dictionary[tag].vr
        if vr in ["DS", "FL", "FD"]:
            value = [float(x) for x in value]
        elif vr in ["IS", "SL", "SS", "UL", "US"]:
            value = [int(x) for x in value]

        query.add(tag, value)

    get_syntax = getattr(
        odil.registry,
        "{}RootQueryRetrieveInformationModelGet".format(level.capitalize()))

    transfer_syntaxes = [
        odil.registry.ImplicitVRLittleEndian,
        odil.registry.ExplicitVRLittleEndian
    ]

    get_pc = odil.AssociationParameters.PresentationContext(
        1, get_syntax, transfer_syntaxes,
        odil.AssociationParameters.PresentationContext.Role.SCU)

    abstract_syntaxes = find_abstract_syntaxes(host, port, calling_ae_title,
                                               called_ae_title, level, keys)
    if not abstract_syntaxes:
        # Negotiate ALL storage syntaxes. Is there a better way to do this?
        abstract_syntaxes = [
            entry.key() for entry in odil.registry.uids_dictionary
            if entry.data().name.endswith("Storage")
        ]
    if len(abstract_syntaxes) > 126:
        raise Exception("Too many storage syntaxes")
    storage_pcs = [
        odil.AssociationParameters.PresentationContext(
            2 * (i + 1) + 1, uid, transfer_syntaxes,
            odil.AssociationParameters.PresentationContext.Role.SCP)
        for i, uid in enumerate(abstract_syntaxes)
    ]

    association = odil.Association()
    association.set_peer_host(host)
    association.set_peer_port(port)
    association.update_parameters()\
        .set_calling_ae_title(calling_ae_title)\
        .set_called_ae_title(called_ae_title) \
        .set_presentation_contexts([get_pc]+storage_pcs)
    association.associate()
    logging.info("Association established")

    get = odil.GetSCU(association)
    get.set_affected_sop_class(get_syntax)

    class Callback(object):
        def __init__(self, directory):
            self.directory = directory
            self.completed = 0
            self.remaining = 0
            self.failed = 0
            self.warning = 0
            self.stored = {}
            self.files = []
            self._study_ids = {}
            self._series_ids = {}

        def store(self, data_set):
            specific_character_set = odil.Value.Strings()
            if "SpecificCharacterSet" in data_set:
                specific_character_set = data_set.as_string(
                    "SpecificCharacterSet")
            as_unicode = lambda x: odil.as_unicode(x, specific_character_set)

            if layout == "flat":
                directory = ""
            elif layout == "tree":
                # Patient directory: <PatientName> or <PatientID>.
                patient_directory = None
                if "PatientName" in data_set and data_set.as_string(
                        "PatientName"):
                    patient_directory = data_set.as_string("PatientName")[0]
                else:
                    patient_directory = data_set.as_string("PatientID")[0]
                patient_directory = as_unicode(patient_directory)

                # Study directory: <StudyID>_<StudyDescription>, both parts are
                # optional. If both tags are missing or empty, default to a
                # numeric index based on StudyInstanceUID.
                study_directory = []
                if "StudyID" in data_set and data_set.as_string("StudyID"):
                    study_directory.append(data_set.as_string("StudyID")[0])
                if ("StudyDescription" in data_set
                        and data_set.as_string("StudyDescription")):
                    study_directory.append(
                        data_set.as_string("StudyDescription")[0])

                if not study_directory:
                    study_instance_uid = data_set.as_string(
                        "StudyInstanceUID")[0]
                    study_directory.append(
                        self._study_ids.setdefault(study_instance_uid,
                                                   1 + len(self._study_ids)))

                study_directory = "_".join(
                    as_unicode(x) for x in study_directory)

                # Study directory: <SeriesNumber>_<SeriesDescription>, both
                # parts are optional. If both tags are missing or empty, default
                # to a numeric index based on SeriesInstanceUID.
                series_directory = []
                if "SeriesNumber" in data_set and data_set.as_int(
                        "SeriesNumber"):
                    series_directory.append(
                        str(data_set.as_int("SeriesNumber")[0]))
                if ("SeriesDescription" in data_set
                        and data_set.as_string("SeriesDescription")):
                    series_directory.append(
                        data_set.as_string("SeriesDescription")[0])

                if not series_directory:
                    series_instance_uid = data_set.as_string(
                        "series_instance_uid")[0]
                    series_directory.append(
                        self._series_ids.setdefault(series_instance_uid,
                                                    1 + len(self._series_ids)))

                series_directory = "_".join(
                    as_unicode(x) for x in series_directory)

                if iso_9660:
                    patient_directory = to_iso_9660(patient_directory)
                    study_directory = to_iso_9660(study_directory)
                    series_directory = to_iso_9660(series_directory)
                directory = os.path.join(patient_directory, study_directory,
                                         series_directory)
                if not os.path.isdir(os.path.join(self.directory, directory)):
                    os.makedirs(os.path.join(self.directory, directory))
            else:
                raise NotImplementedError()

            self.stored.setdefault(directory, 0)

            if iso_9660:
                filename = "IM{:06d}".format(1 + self.stored[directory])
            else:
                filename = as_unicode(data_set.as_string("SOPInstanceUID")[0])

            with odil.open(os.path.join(self.directory, directory, filename),
                           "wb") as fd:
                odil.Writer.write_file(data_set, fd)

            self.stored[directory] += 1
            self.files.append(os.path.join(directory, filename))

        def get(self, message):
            for type_ in ["completed", "remaining", "failed", "warning"]:
                base = "number_of_{}_sub_operations".format(type_)
                if getattr(message, "has_{}".format(base))():
                    setattr(self, type_,
                            getattr(message, "get_{}".format(base))())
            logging.info(
                "Remaining: {}, completed: {}, failed: {}, warning: {}".format(
                    self.remaining, self.completed, self.failed, self.warning))

    if not os.path.isdir(directory):
        os.makedirs(directory)
    if len(os.listdir(directory)):
        logging.warning("{} is not empty".format(directory))

    callback = Callback(directory)
    get.get(query, callback.store, callback.get)
    print("Completed: {}, remaining: {}, failed: {}, warning: {}".format(
        callback.completed, callback.remaining, callback.failed,
        callback.warning))

    association.release()
    logging.info("Association released")

    if dicomdir:
        logging.info("Creating DICOMDIR")
        create_dicomdir([os.path.join(directory, x) for x in callback.files],
                        directory, patient_key, study_key, series_key,
                        image_key)