Import standard tags to a DICOM file with pydicom

105 views Asked by At

I am trying to create a program that can add multiple undefined tags in DICOM files. For the moment, I'd import the tags and values thanks to a CSV file.

This is my current code, it parse through the csv file and add the tags to the dataset of the dicom file

for index, row in tags_df.iterrows():
    ds = dicom.read_file(row["Label")
    row_tags = row.drop("Label")
    for col, val in row_tags.items():
        try:
            tag = Tag(col)
        except:
            print(f"{col} is not a valid tag")
            exit(-1)
        
        print(f"{tag} {col} : {dictionary_VR(tag)} with {val} encoded by {type(val)}")
        ds.add(dicom.DataElement(tag, dictionary_VR(tag), val))

And this is the output on the command line :

(0010, 0010) PatientName : PN with Fly encoded by <class 'str'>
(0010, 0020) PatientID : LO with 42 encoded by <class 'int'>
~/.local/lib/python3.10/site-packages/pydicom/valuerep.py:443: UserWarning: A value of type 'int' cannot be assigned to a tag with VR LO.
  warnings.warn(msg)
(0020, 0010) StudyID : SH with 4123274 encoded by <class 'int'>
~/.local/lib/python3.10/site-packages/pydicom/valuerep.py:443: UserWarning: A value of type 'int' cannot be assigned to a tag with VR SH.
  warnings.warn(msg)
(0020, 000d) StudyInstanceUID : UI with 1.2.840.113745.101000.1008000.38179.6792.6324567 encoded by <class 'str'>
(0020, 000e) SeriesInstanceUID : UI with 1.3.12.2.1107.5.99.1.24063.4.0.446793548272429 encoded by <class 'str'>
(0020, 0011) SeriesNumber : IS with 4 encoded by <class 'int'>
(0020, 0013) InstanceNumber : IS with 1 encoded by <class 'int'>
(0008, 0022) AcquisitionDate : DA with 20231110 encoded by <class 'int'>
~/.local/lib/python3.10/site-packages/pydicom/valuerep.py:443: UserWarning: A value of type 'int' cannot be assigned to a tag with VR DA.
  warnings.warn(msg)
(0028, 0100) BitsAllocated : US with 16 encoded by <class 'int'>

How can I automatically check that the when I add the tag to the Dataset, the "val" is in the right type? (Depending on the known ValueRepresentation).

For example, this is a DA variable "20231110", pandas will read it as an integer but I need to have it as a string. But at the same moment, I can't cast str() to every variable, because BitsAllocated Tag needs an int (or sends a warning)

1

There are 1 answers

0
Broot On BEST ANSWER

As mentionned on a comment made on this post from @MrBeanBremen, pydicom has sets that contains what types are needed for which VR.

The code looks like this now :

FILE_NAME = "Label"

def check_cast(vr, val):
    if vr == VR.AT:
        # if it's an Attribute
        return Tag(val)
    if vr in STR_VR:
        return str(val)
    
    if vr in INT_VR:
        return int(val)
    
    if vr in FLOAT_VR:
        return float(val)
    
    if vr in BYTES_VR:
        return bytes(val)
    
    raise NotImplementedError("cast for SQ not implemented")
    

def update_tags(files : list, tags : QFileInfo):
    warnings.filterwarnings("error")
    files = {file.baseName():file for file in files}
    tags_df = pd.read_csv(tags.absoluteFilePath(), delimiter=';')

    #Check that all the columns (except the name of the file) are DICOM Standard tags
    for series_name, _ in tags_df.items():
        if series_name != FILE_NAME:
            try:
                tag = Tag(series_name)
            except:
                print(f"{series_name} is not a valid tag")
                return -1
    
    print(tags_df.shape)

    for index, row in tags_df.iterrows():
        image_label = row[FILE_NAME]

        if not image_label in files:
            print(f"{image_label} has not been selected")
            continue

        dicom_file = files[image_label]
        
        ds = dicom.read_file(dicom_file.absoluteFilePath())

        row_tags = row.drop(FILE_NAME)

        for col, val in row_tags.items():

            #already checked that the Tag exists
            tag = Tag(col)
            
            try:
                #print(f"{tag} {col} : {dictionary_VR(tag)} with {val} encoded by {type(val)}")
                VR = dictionary_VR(tag)
                ds.add(dicom.DataElement(tag, VR, check_cast(VR,val)))
            except Exception as error:
                print(f"{image_label} : error for {tag} {col} - {val} : {error}")
                #continue even if a tag wasn't added

        ds.save_as(dicom_file.absoluteFilePath())
    
    warnings.resetwarnings()
    return 0

The warning were count as errors as pydicom only sends a warning if the data isn't the right type.