pythondicompydicom

Import standard tags to a DICOM file with pydicom


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)


Solution

  • 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.