diff --git a/mu_map/file/dicom.py b/mu_map/file/dicom.py index 9ae6bc32393ae70b294ab7978496a098dfcf95ae..fd9754e2ae6946470f0ed129436dc82f17d1d4b3 100644 --- a/mu_map/file/dicom.py +++ b/mu_map/file/dicom.py @@ -98,34 +98,64 @@ def parse_age(patient_age: str) -> int: return int(_num) -def load_dcm(filename: str) -> Tuple[DICOM, np.ndarray]: +def load_dcm(filename: str, direction: float = 0.0) -> Tuple[DICOM, np.ndarray]: """ Load a DICOM image, the data as a numpy array and apply normalization of the Siemens SPECT/CT Scanner. :param filename: filename of the DICOM image + :param direction: other than 0 changes the stacking order of slices to the desired direction :return: the dicom header and the scaled image as a numpy array """ dcm = pydicom.dcmread(filename) + image = dcm.pixel_array + if DCM_TAG_PIXEL_SCALE_FACTOR in dcm: - image = dcm.pixel_array / dcm[DCM_TAG_PIXEL_SCALE_FACTOR].value - else: - image = dcm.pixel_array + image = image / dcm[DCM_TAG_PIXEL_SCALE_FACTOR].value + + dcm, image = to_direction((dcm, image), direction=direction) return dcm, image -def load_dcm_img(filename: str) -> np.ndarray: +def load_dcm_img( + filename: str, + direction: float = 0.0, +) -> np.ndarray: """ Load a DICOM image as a numpy array and apply normalization of the Siemens SPECT/CT Scanner. :param filename: filename of the DICOM image + :param direction: other than 0 changes the stacking order of slices to the desired direction :return: the image scaled and loaded into a numpy array """ - _, image = load_dcm(filename) + _, image = load_dcm(filename, direction=direction) return image +def to_direction( + dcm: Tuple[DICOM, np.ndarray], direction: float = 1 +) -> Tuple[DICOM, np.ndarray]: + """ + Change the stacking direction of slices in a DICOM image. + The direction is specified by the sign of the [Spacing Between Slices](https://dicom.innolitics.com/ciods/nm-image/nm-reconstruction/00180088) parameter. + + :param dcm: a tuple of a DICOM header and an image + :param direction: the desired stacking direction as a float (>0 positive, <0 negative, =0 stay as it is) + :return: dicom header (with values updated) and image according to the desired stacking order + """ + dcm, image = dcm + spacing_between_slices = float(dcm.SpacingBetweenSlices) + if spacing_between_slices * direction < 0: + dcm.DetectorInformationSequence[0].ImagePositionPatient[2] *= ( + image.shape[0] * spacing_between_slices + ) + dcm.SpacingBetweenSlices = -spacing_between_slices + + image = image[::-1] + return dcm, image + + def scale_image(image: np.ndarray, initial_scale=10000000) -> Tuple[np.ndarray, float]: """ For memory efficiency, the Siemens SPECT/CT does not store images as floating point