-
Notifications
You must be signed in to change notification settings - Fork 1
Reference DICOM Sequence
Welcome to the DAMS-dicom-anonymizer wiki!
First of all, I had to perform some metatag corrections on my segmentations since some tags were incorrect. The tags were corrupted by the segmentation tool I have used to create the masks (not open source, not commercial, long story). Therefore, first I had to generate a new SeriesInstanceUID
and SOPInstanceUID
using pydicom.uid.generate_uid()
. Then, I corrected the InstanceNumber
for each slice, since in my original segmentations it was the same number for all slices. Last, I created some random dumb SeriesNumber
, which was different than the SeriesNumber from the Source CTs. I needed the SeriesNumber to be able to load in my Annotation Software and database (I worked with Brainlab's Quentry database storage solution).
The code for these is in the def encode_segmentations_dcm_tags(rootdir, patient_name, patient_id, patient_dob)
. Most probably you won't need to run this function.
Now, the cool fun stuff (in my personal subjective opinion). As far as I am aware at this point when I am writing the ReadMe, the way that the segmentations and source images are "connected" for training, segmentation, evaluation purposes (etc, you name it), it's by either having them in the same folder, or in some other folders plus having a CSV/Text/Excel file more often that in tabular format which stores the paths to the (source) image and the other images related to it.
I wanted to avoid this file system path generation, because I either forget where I place my files, or I move them around a lot, or my admin changes the name of my database folder (jk). That being said, I discovered this 2 cool metatags which are actually Metatags Sequences, i.e., they hold several metatags under them , in a parent-child type of relationship. It's important to note that these tags are actually Sequences because they are edited and read in a different manner than simple non-hierachical tags.
The tags that I used are:
I used the ReferencedImageSequence
to store the relation between the tumor and ablation segmentation. Thus, the tumor segmentation will store the SeriesInstanceUID
, SOPClassUID
and lesion number ReferencedSegmentNumber
of the ablation segmentation and vice-versa. The SourceImageSequence
contains the SeriesInstanceUID
of the original initial CT source image from which the segmentation mask was derived.
The library:
from pydicom import uid
from pydicom.dataset import Dataset
from pydicom.sequence import Sequence
The code:
def add_general_reference_segmentation(dataset_segm,
ReferencedSeriesInstanceUID_segm,
ReferencedSOPInstanceUID_src,
StudyInstanceUID_src,
segment_label,
lesion_number
):
"""
`Add Reference to the tumour/ablation and source img in the DICOM segmentation metatags.`
`:param dataset_segm: dcm file read with pydicom library`
`:param ReferencedSOPInstanceUID_segm: SeriesInstanceUID of the related segmentation file (tumour or ablation)`
`:param ReferencedSOPInstanceUID_src: SeriesInstanceUID of the source image`
`:param StudyInstanceUID_src: StudyInstanceUID of the source image`
`:param segment_label: text describing whether is tumor or ablation`
`:param: lesion_number: a int identifying which lesion was this`
`:return: dicom single file/slice with new General Reference Sequence Tags`
"""
if segment_label == "Lession":
dataset_segm.SegmentLabel = "Tumor"
elif segment_label == "AblationZone":
dataset_segm.SegmentLabel = "Ablation"
dataset_segm.StudyInstanceUID = StudyInstanceUID_src
dataset_segm.SegmentationType = "BINARY"
dataset_segm.SegmentAlgorithmType = "SEMIAUTOMATIC"
dataset_segm.DerivationDescription = "CasOneIR"
dataset_segm.ImageType = "DERIVED\PRIMARY"
Segm_ds = Dataset()
Segm_ds.ReferencedSOPInstanceUID = ReferencedSeriesInstanceUID_segm
Segm_ds.ReferencedSOPClassUID = dataset_segm.SOPClassUID
Segm_ds.ReferencedSegmentNumber = lesion_number
Source_ds = Dataset()
Source_ds.ReferencedSOPInstanceUID = ReferencedSOPInstanceUID_src
dataset_segm.ReferencedImageSequence = Sequence([Segm_ds])
dataset_segm.SourceImageSequence = Sequence([Source_ds])
return dataset_segm
Here's a screenshot of both of their definitions:
#TODO: add more info on how the mapping is retrieved using dictionary keys and values.