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