Source code for deid.dicom.tags

__author__ = "Vanessa Sochat"
__copyright__ = "Copyright 2016-2022, Vanessa Sochat"
__license__ = "MIT"

import re

from pydicom._dicom_dict import DicomDictionary, RepeatersDictionary
from pydicom.sequence import Sequence
from pydicom.tag import Tag, tag_in_exception

from deid.logger import bot

################################################################################
# Functions for Finding / Getting Tags
################################################################################


[docs]def add_tag(identifier, VR="ST", VM=None, name=None, keyword=None): """Add tag will take a string for a tag (e.g., ) and define a new tag for it. By default, we give the type "Short Text." """ tag = Tag("0x" + identifier) manifest = { "tag": tag, "VR": VR, "VM": VM, "keyword": keyword, "name": name, } return manifest
[docs]def get_tag(field): """get_tag will return a dictionary with tag indexed by field. For each entry, a dictionary lookup is included with VR. Parameters ========== field: the keyword to get tag for, eg "PatientIdentityRemoved" """ found = [ {key: value} for key, value in DicomDictionary.items() if value[4] == field ] manifest = None if len(found) > 0: # (VR, VM, Name, Retired, Keyword found = found[0] # shouldn't ever have length > 1 tag = Tag(list(found)[0]) VR, VM, longName, _, keyword = found[tag] manifest = { "tag": tag, "VR": VR, "VM": VM, "keyword": keyword, "name": longName, } return manifest
[docs]def find_tag(term, VR=None, VM=None, retired=False): """find_tag will search over tags in the DicomDictionary and return the tags found to match some term. """ searchin = DicomDictionary if retired: searchin = RepeatersDictionary found = [ value for key, value in searchin.items() if re.search(term, value[4]) or re.search(term, value[2]) ] # Filter by VR, VM, name, these are exact if VR is not None: found = _filter_tags(found, 0, VR) if VM is not None: found = _filter_tags(found, 1, VM) return found
def _filter_tags(tags, idx, fields=None): """filter tags is a helper function to take some list of tags in the format [ (VR, VM, longname, retired, keyword).. ] where each of the items above has some index, idx, and filter that index down to what is provided in fields. """ if not isinstance(fields, list): fields = [fields] return [x for x in tags if x[idx] in fields] ################################################################################ # Manipulating Tags in Data ################################################################################
[docs]def remove_sequences(dicom): """remove sequences from a dicom by removing the associated tag. We use dicom.iterall() to get all nested sequences. Parameters ========== dicom: the loaded dicom to remove sequences """ for elem in dicom.iterall(): if isinstance(elem.value, Sequence) and dicom.get(elem.tag) is not None: del dicom[elem.tag] return dicom
[docs]def update_tag(dicom, field, value): """update tag will update a value in the header, if it exists if not, nothing is added. This check is the only difference between this function and change_tag. If the user wants to add a value (that might not exist) the function add_tag should be used with a private identifier as a string. Parameters ========== dicom: the pydicom.dataset Dataset (pydicom.read_file) field: the name of the field to update value: the value to set, if name is a valid tag """ if field not in dicom: return dicom # Case 1: Dealing with a string tag (field name) if isinstance(field, str): tag = get_tag(field) if tag: dicom.add_new(tag["tag"], tag["VR"], value) else: bot.error("%s is not a valid field to add. Skipping." % (field)) # Case 2: we already have a tag for the field name (type BaseTag) else: tag = dicom.get(field) dicom.add_new(field, tag.VR, value) return dicom
######################################################################### # Private Tags #########################################################################
[docs]def get_private(dicom): """get private tags Parameters ========== dicom: the pydicom.dataset Dataset (pydicom.read_file) """ datasets = [dicom] private_tags = [] while len(datasets) > 0: ds = datasets.pop(0) taglist = sorted(ds.keys()) for tag in taglist: with tag_in_exception(tag): if tag in ds: try: data_element = ds[tag] if data_element.tag.is_private: bot.debug(data_element.name) private_tags.append(data_element) if tag in ds and data_element.VR == "SQ": sequence = data_element.value for dataset in sequence: datasets.append(dataset) except IndexError: bot.debug("tag %s key present without value" % tag) except NotImplementedError: bot.debug("tag %s is invalid, skipping" % tag) return private_tags
[docs]def has_private(dicom): """has_private will return True if the header has private tags Parameters ========== dicom: the pydicom.dataset Dataset (pydicom.read_file) """ private_tags = len(get_private(dicom)) print("Found %s private tags" % private_tags) if private_tags > 0: return True return False