Exemplo n.º 1
0
    def __contains__(self, name):
        """Extend dict.__contains__() to handle DICOM keywords.

        This is called for code like:
        >>> 'SliceLocation' in ds
        True

        Parameters
        ----------
        name : str or int or 2-tuple
            The Element keyword or tag to search for.

        Returns
        -------
        bool
            True if the DataElement is in the Dataset, False otherwise.
        """
        if isinstance(name, (str, compat.text_type)):
            tag = tag_for_keyword(name)
        else:
            try:
                tag = Tag(name)
            except Exception:
                return False
        # Test against None as (0000,0000) is a possible tag
        if tag is not None:
            return dict.__contains__(self, tag)
        else:
            return dict.__contains__(self,
                                     name)  # will no doubt raise an exception
Exemplo n.º 2
0
    def __contains__(self, name):
        """Extend dict.__contains__() to handle DICOM keywords.

        This is called for code like:
        >>> 'SliceLocation' in ds
        True

        Parameters
        ----------
        name : str or int or 2-tuple
            The Element keyword or tag to search for.

        Returns
        -------
        bool
            True if the DataElement is in the Dataset, False otherwise.
        """
        if isinstance(name, (str, compat.text_type)):
            tag = tag_for_keyword(name)
        else:
            try:
                tag = Tag(name)
            except Exception:
                return False
        # Test against None as (0000,0000) is a possible tag
        if tag is not None:
            return dict.__contains__(self, tag)
        else:
            return dict.__contains__(self,
                                     name)  # will no doubt raise an exception
Exemplo n.º 3
0
    def __getattr__(self, name):
        """Intercept requests for Dataset attribute names.

        If `name` matches a DICOM keyword, return the value for the
        DataElement with the corresponding tag.

        Parameters
        ----------
        name
            A DataElement keyword or tag or a class attribute name.

        Returns
        -------
        value
              If `name` matches a DICOM keyword, returns the corresponding
              DataElement's value. Otherwise returns the class attribute's
              value (if present).
        """
        tag = tag_for_keyword(name)
        if tag is None:  # `name` isn't a DICOM element keyword
            # Try the base class attribute getter (fix for issue 332)
            return super(Dataset, self).__getattribute__(name)
        tag = Tag(tag)
        if tag not in self:  # DICOM DataElement not in the Dataset
            # Try the base class attribute getter (fix for issue 332)
            return super(Dataset, self).__getattribute__(name)
        else:
            return self[tag].value
Exemplo n.º 4
0
    def __delattr__(self, name):
        """Intercept requests to delete an attribute by `name`.

        If `name` is a DICOM keyword:
            Delete the corresponding DataElement from the Dataset.
            >>> del ds.PatientName
        Else:
            Delete the class attribute as any other class would do.
            >>> del ds._is_some_attribute

        Parameters
        ----------
        name : str
            The keyword for the DICOM element or the class attribute to delete.
        """
        # First check if a valid DICOM keyword and if we have that data element
        tag = tag_for_keyword(name)
        if tag is not None and tag in self:
            dict.__delitem__(self,
                             tag)  # direct to dict as we know we have key
        # If not a DICOM name in this dataset, check for regular instance name
        #   can't do delete directly, that will call __delattr__ again
        elif name in self.__dict__:
            del self.__dict__[name]
        # Not found, raise an error in same style as python does
        else:
            raise AttributeError(name)
Exemplo n.º 5
0
    def __getattr__(self, name):
        """Intercept requests for Dataset attribute names.

        If `name` matches a DICOM keyword, return the value for the
        DataElement with the corresponding tag.

        Parameters
        ----------
        name
            A DataElement keyword or tag or a class attribute name.

        Returns
        -------
        value
              If `name` matches a DICOM keyword, returns the corresponding
              DataElement's value. Otherwise returns the class attribute's
              value (if present).
        """
        tag = tag_for_keyword(name)
        if tag is None:  # `name` isn't a DICOM element keyword
            # Try the base class attribute getter (fix for issue 332)
            return super(Dataset, self).__getattribute__(name)
        tag = Tag(tag)
        if tag not in self:  # DICOM DataElement not in the Dataset
            # Try the base class attribute getter (fix for issue 332)
            return super(Dataset, self).__getattribute__(name)
        else:
            return self[tag].value
Exemplo n.º 6
0
    def tag(self):
        """Return the element's tag as a pydicom.tag.Tag."""
        tag = self.components[0]
        if self.is_sequence:
            tag = tag.split('[')[0]

        # (gggg,eeee) based tag
        if ',' in tag:
            group, element = tag.split(',')
            if '(' in group:
                group = group.replace('(', '')
            if ')' in element:
                element = element.replace(')', '')

            if len(group) != 4 or len(element) != 4:
                raise ValueError(f"Unable to parse element path component: "
                                 f"'{self.components[0]}'")

            return Tag(group, element)

        # From this point on we assume that a keyword was supplied
        kw = tag
        # Keyword based tag - private keywords not allowed
        if repeater_has_keyword(kw):
            raise ValueError(
                f"Repeating group elements must be specified using "
                f"(gggg,eeee): '{self.components[0]}'")

        tag = tag_for_keyword(kw)
        # Test against None as 0x00000000 is a valid tag
        if tag is not None:
            return Tag(tag)

        raise ValueError(
            f"Unable to parse element path component: '{self.components[0]}'")
Exemplo n.º 7
0
def subfix_AddOrChangeAttrib(ds: Dataset, log: list, error_regexp: str,
                             fix_message: str, keyword: str, value) -> bool:
    fixed = False
    t = Dictionary.tag_for_keyword(keyword)
    if t is None:
        return False
    desc = Dictionary.dictionary_description(t)
    ErrorOccured = False
    log_l = len(log)
    for i in range(0, log_l):
        if re.match(error_regexp, log[i]) is not None:
            msg = mesgtext_cc.ErrorInfo(log[i], fix_message)
            log[i] = msg.getWholeMessage()
            ErrorOccured = True
    if ErrorOccured:
        if keyword in ds:
            ds[keyword].value = value  # just modify
            fixed = True
        else:
            vr = Dictionary.dictionary_VR(t)
            vm = 1
            elem = DataElementX(t, vr, value)
            ds[keyword] = elem
            fixed = True
    return fixed
Exemplo n.º 8
0
def fix_VRForLongitudinalTemporalInformationModified(ds: Dataset,
                                                     log: list) -> bool:
    fixed = False
    msg = mesgtext_cc.ErrorInfo()
    kw = "LongitudinalTemporalInformationModified"
    Error_regex = ".*Invalid Value Representation SH \(CS Required\)" \
             ".*{}.*".format(kw)
    idx = subfix_LookUpRegexInLog(Error_regex, log)
    if len(idx) == 0:
        idx.append(-1)
        log.append("Error - bad VR for {}".format(kw))

    if kw in ds:
        tag = Dictionary.tag_for_keyword(kw)

        if ds[tag].VR == "SH":
            ds[tag].VR = "CS"
            for i in idx:
                msg.msg = log[i]
                msg.fix = "fixed by editing SH to CS"
                msg1 = msg.getWholeMessage()
                log[i] = msg1

            fixed = True
    return fixed
Exemplo n.º 9
0
def fix_RemoveFOVDimensionsWhenZero(ds: Dataset, log: list) -> bool:
    fixed = False
    kw = "FieldOfViewDimensions"
    Error_regex = ".*Value is zero for.*attribute.*Field.*View.*Dimension.*"
    msg = mesgtext_cc.ErrorInfo()

    idx = subfix_LookUpRegexInLog(Error_regex, log)
    if len(idx) == 0:
        idx.append(-1)
        log.append("Error - bad value (=0) for {}".format(kw))
    if kw in ds:
        tag = Dictionary.tag_for_keyword(kw)
        elem = ds[tag]
        for i in elem.value:
            if i == 0:
                fixed = True
                break
        if fixed:
            del ds[kw]
            for i in idx:
                msg.msg = log[i]
                msg.fix = "fixed by removing the attribute"
                msg1 = msg.getWholeMessage()
                log[i] = msg1
    return fixed
def generalfix_CheckAndFixModality(ds: Dataset, log: list) -> bool:
    fixed = False
    modality_sop = {
        CTImageStorageSOPClassUID: 'CT',
        MRImageStorageSOPClassUID: 'MR',
        PETImageStorageSOPClassUID: 'PT',
    }
    if 'SOPClassUID' in ds:
        sop_class = ds['SOPClassUID'].value
    else:
        return False
    if sop_class not in modality_sop:
        return False
    mod_tg = tag_for_keyword('Modality')
    if mod_tg in ds:
        modality = ds[mod_tg].value
    else:
        modality = ''
    if modality == '' or modality != modality_sop[sop_class]:
        ds[mod_tg] = DataElementX(mod_tg, dictionary_VR(mod_tg),
                                  modality_sop[sop_class])
        msg = ErrorInfo()
        msg.msg = 'General Fix - {}'.format("<Modality> is wrong or absent")
        msg.fix = "fixed by reading the <SOPClassUID> and setting <Modality>"\
            " from '{}' to '{}'".format(modality, modality_sop[sop_class])
        log.append(msg.getWholeMessage())
        fixed = True
    return fixed
Exemplo n.º 11
0
    def __delattr__(self, name):
        """Intercept requests to delete an attribute by `name`.

        If `name` is a DICOM keyword:
            Delete the corresponding DataElement from the Dataset.
            >>> del ds.PatientName
        Else:
            Delete the class attribute as any other class would do.
            >>> del ds._is_some_attribute

        Parameters
        ----------
        name : str
            The keyword for the DICOM element or the class attribute to delete.
        """
        # First check if a valid DICOM keyword and if we have that data element
        tag = tag_for_keyword(name)
        if tag is not None and tag in self:
            dict.__delitem__(self,
                             tag)  # direct to dict as we know we have key
        # If not a DICOM name in this dataset, check for regular instance name
        #   can't do delete directly, that will call __delattr__ again
        elif name in self.__dict__:
            del self.__dict__[name]
        # Not found, raise an error in same style as python does
        else:
            raise AttributeError(name)
def get_old_anatomy(ds):
    bpe = tag_for_keyword('BodyPartExamined')
    ars = tag_for_keyword('AnatomicRegionSequence')
    old_bpe = None if bpe not in ds else ds[bpe].value
    old_ars_seq = None if ars not in ds else ds[bpe].value
    old_ars_val = (None, None, None)
    if old_ars_seq is not None:
        if len(old_ars_seq) > 0:
            old_ars_item = old_ars_seq[0]
            cm = None if CodeValue not in old_ars_item else \
                old_ars_item[CodeValue].value
            cv = None if CodeMeaning not in old_ars_item else \
                old_ars_item[CodeMeanin].value
            cs = None if CodingSchemeDesignator not in old_ars_item else \
                old_ars_item[CodingSchemeDesignato].value
            old_ars_val = (cv, cm, cs)
    return old_bpe, old_ars_val
def generalfix_RealWorldValueMappingSequence(ds, log):
    kw = 'RealWorldValueMappingSequence'
    tg = tag_for_keyword(kw)
    if tg in ds:
        v = ds[tg].value
        for i, item in enumerate(v):
            in_key = 'LUTLabel'
            in_tg = tag_for_keyword(in_key)
            if in_tg not in item:
                new_el = DataElementX(in_tg, 'SH', 'Unknown')
                item[in_tg] = new_el
                err = "<{}> {}".format(in_key, validate_vr.tag2str(in_tg))
                msg = ErrorInfo(
                    "General Fix - The item number {} lacks {}".format(i, err),
                    "fixed by adding a new element with value <{}>".format(
                        new_el.value))
                log.append(msg.getWholeMessage())
Exemplo n.º 14
0
 def set_dicom_attribute(self, keyword, value):
     """Sets specified DICOM attribute according to the keyword value pair
     Parameters
     ----------
     keyword : Name of DICOM tag to set value for
     value : Value to set
     """
     if tag_for_keyword(keyword):
         if keyword in self.dataset:
             if dictionary_VR(
                     tag_for_keyword(keyword)) == "SQ" and isinstance(
                         value, list):
                 value = generate_sequence(keyword, value)
             self.dataset[tag_for_keyword(keyword)].value = value
         else:
             if dictionary_VR(
                     tag_for_keyword(keyword)) == "SQ" and isinstance(
                         value, list):
                 value = generate_sequence(keyword, value)
             de = DataElement(tag_for_keyword(keyword),
                              dictionary_VR(tag_for_keyword(keyword)),
                              value)
             self.dataset[tag_for_keyword(keyword)] = de
     else:
         print("Keyword", keyword, "is an unknown DICOM attribute")
def fix_SOPReferencedMacro(ds: Dataset,
                           log: list,
                           suggested_SOPClassUID: dict = {}):
    kw = 'ReferencedStudySequence'
    tg = tag_for_keyword(kw)
    if tg not in ds:
        return
    val = ds[tg].value
    if len(val) == 0:
        del ds[tg]
        return
    i = 0

    while i < len(val):
        item = val[i]
        msg = ErrorInfo()
        if 'ReferencedSOPInstanceUID' not in item:
            msg.msg = 'General Fix - item {}/{} <ReferencedStudySequence>'\
                ' lacks <ReferencedSOPInstanceUID> attribute'.format(i + 1, len(val))
            msg.fix = 'fixed by removint the item'
            log.append(msg.getWholeMessage())
            val.pop(i)
            continue
        if item['ReferencedSOPInstanceUID'].is_empty:
            msg.msg = 'General Fix - item {}/{} <ReferencedStudySequence>'\
                ' holds an empty <ReferencedSOPInstanceUID> attribute'.format(i + 1, len(val))
            msg.fix = 'fixed by removint the item'
            log.append(msg.getWholeMessage())
            val.pop(i)
            continue
        if 'ReferencedSOPClassUID' not in item or\
                item['ReferencedSOPClassUID'].is_empty:
            uid = item['ReferencedSOPInstanceUID'].value
            msg.msg = 'General Fix - item {}/{} <ReferencedStudySequence>'\
                ' lacks <ReferencedSOPClassUID> attribute'.format(i + 1, len(val))
            if uid not in suggested_SOPClassUID:
                msg.fix = 'fixed by removint the item'
                log.append(msg.getWholeMessage())
                val.pop(i)
                continue
            else:
                msg.fix = 'fixed by querying the attribute '\
                    'ReferencedSOPClassUID filling it with {}'.format(
                        suggested_SOPClassUID[uid]
                    )
                log.append(msg.getWholeMessage())
                item['ReferencedSOPClassUID'].value = suggested_SOPClassUID[
                    uid]
        i += 1
    if len(val) == 0:
        msg = ErrorInfo()
        msg.msg = 'General Fix - Attribute <{}> is empty '.format(kw)
        msg.fix = 'fixed by removint the attribute'
        log.append(msg.getWholeMessage())
        del ds[tg]
    return
Exemplo n.º 16
0
def fix_type_based_on_dicom_vm(header):

    exc_keys = []
    for key, val in header.items():
        try:
            vr, vm, _, _, _ = DicomDictionary.get(tag_for_keyword(key))
        except (ValueError, TypeError):
            exc_keys.append(key)
            continue

        if vr != "SQ":
            if vm != "1" and not isinstance(val, list):  # anything else is a list
                header[key] = [val]
            elif vm == "1" and isinstance(val, list):
                if len(val) == 1:
                    header[key] = val[0]
                else:
                    if (
                        vr
                        not in [
                            "UT",
                            "ST",
                            "LT",
                            "FL",
                            "FD",
                            "AT",
                            "OB",
                            "OW",
                            "OF",
                            "SL",
                            "SQ",
                            "SS",
                            "UL",
                            "OB/OW",
                            "OW/OB",
                            "OB or OW",
                            "OW or OB",
                            "UN",
                        ]
                        and "US" not in vr
                    ):
                        val = cast_castable_floats(val)

                        header[key] = "\\".join([str(item) for item in val])
        else:
            for dataset in val:
                if isinstance(dataset, dict):
                    fix_type_based_on_dicom_vm(dataset)
                else:
                    log.warning(
                        "%s SQ list item is not a dictionary - value = %s", key, dataset
                    )
    if len(exc_keys) > 0:
        log.warning(
            "%s Dicom data elements were not type fixed based on VM", len(exc_keys)
        )
Exemplo n.º 17
0
def fix_ByAddingEmptyAttrib(ds: Dataset, element: str) -> str:
    reason = ''
    ttag = tag_for_keyword(element)
    if ttag is not None:
        vr = Dic.dictionary_VR(ttag)
        element = DataElementX(ttag, vr, '')
        element.value = element.empty_value
        ds[ttag] = element
        reason += "fixed by adding empty attribute"
    return reason
def fix_ReferencedImageSequence(ds, log: list) -> bool:
    # This patch is a prticular fixing procedure to replace SOPInstanceUID
    # with ReferencedSOPInstanceUID and SOPClassUID with ReferencedSOPClassUID
    fixed = False
    kw = 'ReferencedImageSequence'
    tg = Dictionary.tag_for_keyword(kw)
    if tg not in ds:
        return True
    val = ds[tg].value
    ref_cls_kw = 'ReferencedSOPClassUID'
    ref_cls_tg = Dictionary.tag_for_keyword(ref_cls_kw)
    ref_inst_kw = 'ReferencedSOPInstanceUID'
    ref_inst_tg = Dictionary.tag_for_keyword(ref_inst_kw)

    i = 0
    while i < len(val):
        item = val[i]
        if 'SOPInstanceUID' in item:
            msg = mesgtext_cc.ErrorInfo()
            msg.msg = "Item {}/{} in <ReferencedImageSequence> holds "\
                "<SOPInstanceUID> instead of <ReferencedSOPInstanceUID>".format(i + 1, len(val))
            msg.fix = "fixed by changing the attribute into <ReferencedSOPInstanceUID>"
            log.append(msg.getWholeMessage())
            item[ref_inst_tg] = DataElementX(ref_inst_tg, 'UI',
                                             item['SOPInstanceUID'].value)
            del item['SOPInstanceUID']
            fixed = True
        if 'SOPClassUID' in item:
            msg = mesgtext_cc.ErrorInfo()
            msg.msg = "Item {}/{} in <ReferencedImageSequence> holds "\
                "<SOPClassUID> instead of <ReferencedSOPClassUID>".format(i + 1, len(val))
            msg.fix = "fixed by changing the attribute into <ReferencedSOPClassUID>"
            log.append(msg.getWholeMessage())
            item[ref_cls_tg] = DataElementX(ref_cls_tg, 'UI',
                                            item['SOPClassUID'].value)
            del item['SOPClassUID']
            fixed = True
        i += 1
    return fixed
Exemplo n.º 19
0
 def __init__(self, fix_msg: str) -> None:
     self.message = fix_msg
     regexp = r'([^-]*)\s-\s(.*):-\>:(.*)\<function(.*)from file:(.*) line_number: (.*)\> \<function(.*)from file:(.*) line_number: (.*)\>'
     m = re.search(regexp, fix_msg)
     if m is None:
         raise MessageError("The message is not fix type")
     self.type = m.group(1)
     self.issue = m.group(2)
     issue_pattern = r'T<([^>]*)>\s(.*)'
     m_issue = re.search(issue_pattern, self.issue)
     if m_issue is not None:
         self.issue_short = m_issue.group(1)
         self.issue = m_issue.group(2)
     else:
         self.issue_short = None
     self.fix = m.group(3)
     self.fun1 = m.group(4)
     file1 = m.group(5)
     line1 = m.group(6)
     self.fun2 = m.group(7)
     file2 = m.group(8)
     line2 = m.group(9)
     self.file1_name = os.path.basename(file1)
     self.file1_link = "{}#L{}".format(file1,
                                       line1).replace(current_dir, git_ws)
     self.file2_name = os.path.basename(file2)
     self.file2_link = "{}#L{}".format(file2,
                                       line2).replace(current_dir, git_ws)
     element_pattern = r'(Element|attribute|keyword)[=\s]{,5}<([^>]*)>'
     m = re.search(element_pattern, self.issue)
     if m is not None:
         self.attribute = m.group(2)
     else:
         self.attribute = None
     if self.attribute is not None:
         self.tag = Dic.tag_for_keyword(self.attribute)
     else:
         ptrn = r'\(0x([0-9A-Fa-f]{4})[,\s]{,2}0x([0-9A-Fa-f]{4})\)'
         m = re.search(ptrn, self.issue)
         if m is not None:
             self.tag = int(m.group(1) + m.group(2), 16)
         else:
             self.tag = None
     module_pattern = r'(Module|Macro)[=\s]{,5}<([^>]*)>'
     m = re.search(module_pattern, self.issue)
     if m is not None:
         self.module_macro = m.group(2)
     else:
         self.module_macro = None
def generalfix_WindowWidth(ds, log):
    fixed = False
    wwkw = 'WindowWidth'
    wwtg = tag_for_keyword(wwkw)
    if wwtg in ds:
        if ds[wwtg].value == 0:
            ds[wwtg].value = 1
            err = "<{}> {}".format(wwkw, validate_vr.tag2str(wwtg))
            msg = ErrorInfo(
                "General Fix - Window width {} "\
                    "is not allowed to be 0".format(err),
                "fixed by replacing it with 1")
            log.append(msg.getWholeMessage())
            fixed = True
    return fixed
Exemplo n.º 21
0
def subfix_UpdateOrInsertCodeAttribute(seqelem: DataElementX, index: int,
                                       kw: str, value: str) -> str:
    text_fun = lambda ds, att: '{}: {}\t'.format(att, ds[att])
    out_msg = ''
    if kw in seqelem.value[index]:
        out_msg = " {} modified <{}> -> <{}>".format(
            kw, seqelem.value[index][kw].value, value)
        seqelem.value[index][kw].value = value
    else:
        out_msg = "{} = <{}> was added".format(kw, value)
        newtag = Dictionary.tag_for_keyword(kw)
        newvr = Dictionary.dictionary_VR(newtag)
        elem = DataElementX(newtag, newvr, value)
        seqelem.value[index].add(elem)
    return out_msg
Exemplo n.º 22
0
Arquivo: util.py Projeto: moloney/dcm
def str_to_tag(in_str: str) -> BaseTag:
    """Convert string representation to pydicom Tag

    The string can be a keyword, or two numbers separated by a comma
    """
    if in_str[0].isupper():
        res = tag_for_keyword(in_str)
        if res is None:
            raise ValueError("Invalid element ID: %s" % in_str)
        return Tag(res)
    try:
        group_num, elem_num = [int(x.strip(), 0) for x in in_str.split(",")]
    except Exception:
        raise ValueError("Invalid element ID: %s" % in_str)
    return Tag(group_num, elem_num)
Exemplo n.º 23
0
 def copy_additional_dicom_attributes(self, dataset_to_copy_from,
                                      dataset_to_copy_to,
                                      additional_dicom_attributes):
     """Copies additional DICOM attributes for this module from one dataset to another
     Parameters
     ----------
     dataset_to_copy_from : Dataset to copy DICOM attributes from
     dataset_to_copy_to : Dataset to copy DICOM attributes to
     additional_dicom_attributes : List of additional DICOM attributes to copy
     """
     for dicom_attribute in additional_dicom_attributes:
         tag = tag_for_keyword(dicom_attribute)
         if dicom_attribute in dataset_to_copy_from:
             dataset_to_copy_to[tag] = dataset_to_copy_from[tag]
         else:
             de = DataElement(tag, dictionary_VR(tag), "")
             dataset_to_copy_to[tag] = de
Exemplo n.º 24
0
def put_attribute_in_path(ds: Dataset, path: list, a: DataElementX):
    if not path:
        if a.tag not in ds:
            ds[a.tag] = a
    else:
        kw = path.pop(0)
        tg = Dictionary.tag_for_keyword(kw)
        vr = Dictionary.dictionary_VR(tg)
        if vr == 'SQ':
            if tg in ds and ds[tg].VM > 0:
                inner_sq = ds[tg]
                item = inner_sq.value[0]
            else:
                item = Dataset()
                new_element = DataElementX(tg, vr, Sequence([item]))
                ds[tg] = new_element
            put_attribute_in_path(item, path, a)
Exemplo n.º 25
0
 def copy_required_dicom_attributes(self, dataset_to_copy_from,
                                    dataset_to_copy_to):
     """Copies required DICOM attributes for this module from one dataset to another
     Parameters
     ----------
     dataset_to_copy_from : Dataset to copy DICOM attributes from
     dataset_to_copy_to : Dataset to copy DICOM attributes to
     """
     for dicom_attribute in self.required_dicom_attributes:
         tag = tag_for_keyword(dicom_attribute)
         if dicom_attribute in dataset_to_copy_from:
             dataset_to_copy_to[tag] = dataset_to_copy_from[tag]
         elif dicom_attribute in dataset_to_copy_to:
             pass
         else:
             de = DataElement(tag, dictionary_VR(tag), "")
             dataset_to_copy_to[tag] = de
Exemplo n.º 26
0
def fix_type_based_on_dicom_vm(header):
    exc_keys = []
    for key, val in header.items():
        try:
            vr, vm, _, _, _ = DicomDictionary.get(tag_for_keyword(key))
        except (ValueError, TypeError):
            exc_keys.append(key)
            continue

        if vr != 'SQ':
            if vm != '1' and not isinstance(val,
                                            list):  # anything else is a list
                header[key] = [val]
        else:
            for dataset in val:
                fix_type_based_on_dicom_vm(dataset)
    if len(exc_keys) > 0:
        log.warning('%s Dicom data elements were not type fixed based on VM',
                    len(exc_keys))
Exemplo n.º 27
0
    def data_element(self, name):
        """Return the DataElement corresponding to the element keyword `name`.

        Parameters
        ----------
        name : str
            A DICOM element keyword.

        Returns
        -------
        pydicom.dataelem.DataElement or None
            For the given DICOM element `keyword`, return the corresponding
            Dataset DataElement if present, None otherwise.
        """
        tag = tag_for_keyword(name)
        # Test against None as (0000,0000) is a possible tag
        if tag is not None:
            return self[tag]
        return None
Exemplo n.º 28
0
def subfix_RemoveAttrib(ds: Dataset, log: list, error_regexp: str,
                        keyword: str) -> bool:
    fixed = False
    t = Dictionary.tag_for_keyword(keyword)
    if t is None:
        return False
    desc = Dictionary.dictionary_description(t)
    ErrorOccured = False
    log_l = len(log)
    for i in range(0, log_l):
        if re.match(error_regexp, log[i]) is not None:
            msg = mesgtext_cc.ErrorInfo(log[i],
                                        "fixed by removing the attribute")
            log[i] = msg.getWholeMessage()
            ErrorOccured = True
    if ErrorOccured:
        del ds[keyword]
        fixed = True
    return fixed
Exemplo n.º 29
0
    def data_element(self, name):
        """Return the DataElement corresponding to the element keyword `name`.

        Parameters
        ----------
        name : str
            A DICOM element keyword.

        Returns
        -------
        pydicom.dataelem.DataElement or None
            For the given DICOM element `keyword`, return the corresponding
            Dataset DataElement if present, None otherwise.
        """
        tag = tag_for_keyword(name)
        # Test against None as (0000,0000) is a possible tag
        if tag is not None:
            return self[tag]
        return None
Exemplo n.º 30
0
    def _copy_attribute(self, dataset: Dataset, keyword: str) -> None:
        """Copies an attribute from `dataset` to `self`.

        Parameters
        ----------
        dataset: pydicom.dataset.Dataset
            DICOM Data Set from which attribute should be copied
        keyword: str
            Keyword of the attribute

        """
        tag = tag_for_keyword(keyword)
        try:
            data_element = dataset[tag]
            logger.debug('copied attribute "{}"'.format(keyword))
        except KeyError:
            logger.debug('skipped attribute "{}"'.format(keyword))
            return
        self.add(data_element)
Exemplo n.º 31
0
def fix_type_based_on_dicom_vm(header):
    exc_keys = []
    for key, val in header.items():
        try:
            vr, vm, _, _, _ = DicomDictionary.get(tag_for_keyword(key))
        except (ValueError, TypeError):
            exc_keys.append(key)
            continue

        if vr != 'SQ':
            if vm != '1' and not isinstance(val, list):  # anything else is a list
                header[key] = [val]
        elif not isinstance(val, list):
            # To deal with DataElement that pydicom did not read as sequence
            # (e.g. stored as OB and pydicom parsing them as binary string)
            exc_keys.append(key)
        else:
            for dataset in val:
                fix_type_based_on_dicom_vm(dataset)
    if len(exc_keys) > 0:
        log.warning('%s Dicom data elements were not type fixed based on VM', len(exc_keys))
Exemplo n.º 32
0
    def __setattr__(self, name, value):
        """Intercept any attempts to set a value for an instance attribute.

        If name is a DICOM keyword, set the corresponding tag and DataElement.
        Else, set an instance (python) attribute as any other class would do.

        Parameters
        ----------
        name : str
            The element keyword for the DataElement you wish to add/change. If
            `name` is not a DICOM element keyword then this will be the
            name of the attribute to be added/changed.
        value
            The value for the attribute to be added/changed.
        """
        tag = tag_for_keyword(name)
        if tag is not None:  # successfully mapped name to a tag
            if tag not in self:
                # don't have this tag yet->create the data_element instance
                VR = dictionary_VR(tag)
                data_element = DataElement(tag, VR, value)
            else:
                # already have this data_element, just changing its value
                data_element = self[tag]
                data_element.value = value
            # Now have data_element - store it in this dict
            self[tag] = data_element
        elif repeater_has_keyword(name):
            # Check if `name` is repeaters element
            raise ValueError('{} is a DICOM repeating group '
                             'element and must be added using '
                             'the add() or add_new() methods.'
                             .format(name))
        else:
            # name not in dicom dictionary - setting a non-dicom instance
            # attribute
            # XXX note if user mis-spells a dicom data_element - no error!!!
            super(Dataset, self).__setattr__(name, value)
Exemplo n.º 33
0
    def __setattr__(self, name, value):
        """Intercept any attempts to set a value for an instance attribute.

        If name is a DICOM keyword, set the corresponding tag and DataElement.
        Else, set an instance (python) attribute as any other class would do.

        Parameters
        ----------
        name : str
            The element keyword for the DataElement you wish to add/change. If
            `name` is not a DICOM element keyword then this will be the
            name of the attribute to be added/changed.
        value
            The value for the attribute to be added/changed.
        """
        tag = tag_for_keyword(name)
        if tag is not None:  # successfully mapped name to a tag
            if tag not in self:
                # don't have this tag yet->create the data_element instance
                VR = dictionary_VR(tag)
                data_element = DataElement(tag, VR, value)
            else:
                # already have this data_element, just changing its value
                data_element = self[tag]
                data_element.value = value
            # Now have data_element - store it in this dict
            self[tag] = data_element
        elif repeater_has_keyword(name):
            # Check if `name` is repeaters element
            raise ValueError('{} is a DICOM repeating group '
                             'element and must be added using '
                             'the add() or add_new() methods.'
                             .format(name))
        else:
            # name not in dicom dictionary - setting a non-dicom instance
            # attribute
            # XXX note if user mis-spells a dicom data_element - no error!!!
            super(Dataset, self).__setattr__(name, value)
Exemplo n.º 34
0
def update_and_insert_additional_DICOM_attributes_in_ds(
        ds, keyword_and_value_dict):
    # For every keyword
    for keyword in keyword_and_value_dict:
        # Get corresponding tag and value
        tag = tag_for_keyword(keyword)
        # Verify that it is a valid keyword
        if tag is None:
            print("Unknown DICOM attribute:", keyword)
            continue
        # Get corresponding value
        value = None
        if dictionary_VR(tag) == "SQ":
            value = generate_sequence(keyword, keyword_and_value_dict[keyword])
        else:
            value = keyword_and_value_dict[keyword]
        # If keyword already set, update its value, otherwise, create a new data element
        if keyword in ds:
            ds[tag].value = value
        else:
            ds[tag] = DataElement(tag, dictionary_VR(tag), value)
    # Return edited dataset
    return ds
Exemplo n.º 35
0
 def __init__(self, issue_msg: str) -> None:
     self.message = issue_msg
     regexp = r'.*(Error|Warning)([-\s]*)(.*)'
     m = re.search(regexp, issue_msg)
     if m is None:
         raise MessageError('The issue is not a right type')
     self.type = m.group(1)
     self.issue_msg = m.group(3)
     issue_pattern = r'T<([^>]*)>\s(.*)'
     m_issue = re.search(issue_pattern, self.issue_msg)
     if m_issue is not None:
         self.issue_short = m_issue.group(1)
         self.issue = m_issue.group(2)
     else:
         self.issue_short = None
     element_pattern = r'(Element|attribute|keyword)[=\s]{,5}<([^>]*)>'
     m = re.search(element_pattern, issue_msg)
     if m is not None:
         self.attribute = m.group(2)
     else:
         self.attribute = None
     if self.attribute is not None:
         self.tag = Dic.tag_for_keyword(self.attribute)
     else:
         ptrn = r"\(0x([0-9A-Fa-f]{4})[,\s]*0x([0-9A-Fa-f]{4})\)"
         m = re.search(ptrn, issue_msg)
         if m is not None:
             self.tag = int(m.group(1) + m.group(2), 16)
         else:
             self.tag = None
     module_pattern = r'(Module|Macro)[=\s]{,5}<([^>]*)>'
     m = re.search(module_pattern, issue_msg)
     if m is not None:
         self.module_macro = m.group(2)
     else:
         self.module_macro = None
Exemplo n.º 36
0
def data_element_generator(fp,
                           is_implicit_VR,
                           is_little_endian,
                           stop_when=None,
                           defer_size=None,
                           encoding=default_encoding,
                           specific_tags=None):

    """Create a generator to efficiently return the raw data elements.

    Parameters
    ----------
    fp : file-like object
    is_implicit_VR : boolean
    is_little_endian : boolean
    stop_when : None, callable, optional
        If None (default), then the whole file is read.
        A callable which takes tag, VR, length,
        and returns True or False. If it returns True,
        read_data_element will just return.
    defer_size : int, str, None, optional
        See ``dcmread`` for parameter info.
    encoding :
        Encoding scheme
    specific_tags : list or None
        See ``dcmread`` for parameter info.

    Returns
    -------
    VR : None if implicit VR, otherwise the VR read from the file
    length :
        the length as in the DICOM data element (could be
        DICOM "undefined length" 0xffffffffL)
    value_bytes :
        the raw bytes from the DICOM file
        (not parsed into python types)
    is_little_endian : boolean
        True if transfer syntax is little endian; else False.
    """
    # Summary of DICOM standard PS3.5-2008 chapter 7:
    # If Implicit VR, data element is:
    #    tag, 4-byte length, value.
    #        The 4-byte length can be FFFFFFFF (undefined length)*
    #
    # If Explicit VR:
    #    if OB, OW, OF, SQ, UN, or UT:
    #       tag, VR, 2-bytes reserved (both zero), 4-byte length, value
    #           For all but UT, the length can be FFFFFFFF (undefined length)*
    #   else: (any other VR)
    #       tag, VR, (2 byte length), value
    # * for undefined length, a Sequence Delimitation Item marks the end
    #        of the Value Field.
    # Note, except for the special_VRs, both impl and expl VR use 8 bytes;
    #    the special VRs follow the 8 bytes with a 4-byte length

    # With a generator, state is stored, so we can break down
    #    into the individual cases, and not have to check them again for each
    #    data element

    if is_little_endian:
        endian_chr = "<"
    else:
        endian_chr = ">"
    if is_implicit_VR:
        element_struct = Struct(endian_chr + "HHL")
    else:  # Explicit VR
        # tag, VR, 2-byte length (or 0 if special VRs)
        element_struct = Struct(endian_chr + "HH2sH")
        extra_length_struct = Struct(endian_chr + "L")  # for special VRs
        extra_length_unpack = extra_length_struct.unpack  # for lookup speed

    # Make local variables so have faster lookup
    fp_read = fp.read
    fp_tell = fp.tell
    logger_debug = logger.debug
    debugging = config.debugging
    element_struct_unpack = element_struct.unpack
    defer_size = size_in_bytes(defer_size)

    tag_set = set()
    if specific_tags is not None:
        for tag in specific_tags:
            if isinstance(tag, (str, compat.text_type)):
                tag = Tag(tag_for_keyword(tag))
            if isinstance(tag, BaseTag):
                tag_set.add(tag)
        tag_set.add(Tag(0x08, 0x05))
    has_tag_set = len(tag_set) > 0

    while True:
        # Read tag, VR, length, get ready to read value
        bytes_read = fp_read(8)
        if len(bytes_read) < 8:
            return  # at end of file
        if debugging:
            debug_msg = "{0:08x}: {1}".format(fp.tell() - 8,
                                              bytes2hex(bytes_read))

        if is_implicit_VR:
            # must reset VR each time; could have set last iteration (e.g. SQ)
            VR = None
            group, elem, length = element_struct_unpack(bytes_read)
        else:  # explicit VR
            group, elem, VR, length = element_struct_unpack(bytes_read)
            if not in_py2:
                VR = VR.decode(default_encoding)
            if VR in extra_length_VRs:
                bytes_read = fp_read(4)
                length = extra_length_unpack(bytes_read)[0]
                if debugging:
                    debug_msg += " " + bytes2hex(bytes_read)
        if debugging:
            debug_msg = "%-47s  (%04x, %04x)" % (debug_msg, group, elem)
            if not is_implicit_VR:
                debug_msg += " %s " % VR
            if length != 0xFFFFFFFF:
                debug_msg += "Length: %d" % length
            else:
                debug_msg += "Length: Undefined length (FFFFFFFF)"
            logger_debug(debug_msg)

        # Positioned to read the value, but may not want to -- check stop_when
        value_tell = fp_tell()
        tag = TupleTag((group, elem))
        if stop_when is not None:
            # XXX VR may be None here!! Should stop_when just take tag?
            if stop_when(tag, VR, length):
                if debugging:
                    logger_debug("Reading ended by stop_when callback. "
                                 "Rewinding to start of data element.")
                rewind_length = 8
                if not is_implicit_VR and VR in extra_length_VRs:
                    rewind_length += 4
                fp.seek(value_tell - rewind_length)
                return

        # Reading the value
        # First case (most common): reading a value with a defined length
        if length != 0xFFFFFFFF:
            # don't defer loading of Specific Character Set value as it is
            # needed immediately to get the character encoding for other tags
            if has_tag_set and tag not in tag_set:
                # skip the tag if not in specific tags
                fp.seek(fp_tell() + length)
                continue

            if (defer_size is not None and length > defer_size and
                    tag != BaseTag(0x00080005)):
                # Flag as deferred by setting value to None, and skip bytes
                value = None
                logger_debug("Defer size exceeded. "
                             "Skipping forward to next data element.")
                fp.seek(fp_tell() + length)
            else:
                value = fp_read(length)
                if debugging:
                    dotdot = "   "
                    if length > 12:
                        dotdot = "..."
                    logger_debug("%08x: %-34s %s %r %s" % (value_tell,
                                                           bytes2hex(
                                                               value[:12]),
                                                           dotdot,
                                                           value[:12], dotdot))

            # If the tag is (0008,0005) Specific Character Set, then store it
            if tag == BaseTag(0x00080005):
                from pydicom.values import convert_string
                encoding = convert_string(value, is_little_endian)
                # Store the encoding value in the generator
                # for use with future elements (SQs)
                encoding = convert_encodings(encoding)

            yield RawDataElement(tag, VR, length, value, value_tell,
                                 is_implicit_VR, is_little_endian)

        # Second case: undefined length - must seek to delimiter,
        # unless is SQ type, in which case is easier to parse it, because
        # undefined length SQs and items of undefined lengths can be nested
        # and it would be error-prone to read to the correct outer delimiter
        else:
            # Try to look up type to see if is a SQ
            # if private tag, won't be able to look it up in dictionary,
            #   in which case just ignore it and read the bytes unless it is
            #   identified as a Sequence
            if VR is None:
                try:
                    VR = dictionary_VR(tag)
                except KeyError:
                    # Look ahead to see if it consists of items
                    # and is thus a SQ
                    next_tag = TupleTag(unpack(endian_chr + "HH", fp_read(4)))
                    # Rewind the file
                    fp.seek(fp_tell() - 4)
                    if next_tag == ItemTag:
                        VR = 'SQ'

            if VR == 'SQ':
                if debugging:
                    msg = "{0:08x}: Reading/parsing undefined length sequence"
                    logger_debug(msg.format(fp_tell()))
                seq = read_sequence(fp, is_implicit_VR,
                                    is_little_endian, length, encoding)
                if has_tag_set and tag not in tag_set:
                    continue
                yield DataElement(tag, VR, seq, value_tell,
                                  is_undefined_length=True)
            else:
                delimiter = SequenceDelimiterTag
                if debugging:
                    logger_debug("Reading undefined length data element")
                value = read_undefined_length_value(fp, is_little_endian,
                                                    delimiter, defer_size)

                # If the tag is (0008,0005) Specific Character Set,
                # then store it
                if tag == (0x08, 0x05):
                    from pydicom.values import convert_string
                    encoding = convert_string(value, is_little_endian)
                    # Store the encoding value in the generator for use
                    # with future elements (SQs)
                    encoding = convert_encodings(encoding)

                # tags with undefined length are skipped after read
                if has_tag_set and tag not in tag_set:
                    continue
                yield RawDataElement(tag, VR, length, value, value_tell,
                                     is_implicit_VR, is_little_endian)
Exemplo n.º 37
0
def Tag(arg, arg2=None):
    """Create a Tag.

    General function for creating a Tag in any of the standard forms:

    * Tag(0x00100015)
    * Tag('0x00100015')
    * Tag((0x10, 0x50))
    * Tag(('0x10', '0x50'))
    * Tag(0x0010, 0x0015)
    * Tag(0x10, 0x15)
    * Tag(2341, 0x10)
    * Tag('0xFE', '0x0010')
    * Tag("PatientName")

    Parameters
    ----------
    arg : int or str or 2-tuple/list
        If int or str, then either the group or the combined
        group/element number of the DICOM tag. If 2-tuple/list
        then the (group, element) numbers as int or str.
    arg2 : int or str, optional
        The element number of the DICOM tag, required when
        `arg` only contains the group number of the tag.

    Returns
    -------
    pydicom.tag.BaseTag
    """
    if isinstance(arg, BaseTag):
        return arg

    if arg2 is not None:
        arg = (arg, arg2)  # act as if was passed a single tuple

    if isinstance(arg, (tuple, list)):
        if len(arg) != 2:
            raise ValueError("Tag must be an int or a 2-tuple")

        valid = False
        if isinstance(arg[0], compat.string_types):
            valid = isinstance(arg[1], (str, compat.string_types))
            if valid:
                arg = (int(arg[0], 16), int(arg[1], 16))
        elif isinstance(arg[0], compat.number_types):
            valid = isinstance(arg[1], compat.number_types)
        if not valid:
            raise ValueError("Both arguments for Tag must be the same type, "
                             "either string or int.")

        if arg[0] > 0xFFFF or arg[1] > 0xFFFF:
            raise OverflowError("Groups and elements of tags must each "
                                "be <=2 byte integers")

        long_value = (arg[0] << 16) | arg[1]

    # Single str parameter
    elif isinstance(arg, (str, compat.text_type)):
        try:
            long_value = int(arg, 16)
            if long_value > 0xFFFFFFFF:
                raise OverflowError("Tags are limited to 32-bit length; "
                                    "tag {0!r}"
                                    .format(long_value))
        except ValueError:
            # Try a DICOM keyword
            from pydicom.datadict import tag_for_keyword
            long_value = tag_for_keyword(arg)
            if long_value is None:
                raise ValueError("'{}' is not a valid int or DICOM keyword"
                                 .format(arg))
    # Single int parameter
    else:
        long_value = arg
        if long_value > 0xFFFFFFFF:
            raise OverflowError("Tags are limited to 32-bit length; tag {0!r}"
                                .format(long_value))

    if long_value < 0:
        raise ValueError("Tags must be positive.")

    return BaseTag(long_value)