AutoSeg4ETICA / nnunet /dataset_conversion /Task056_Verse_normalize_orientation.py
Chris Xiao
upload files
c642393
# Copyright 2020 Division of Medical Image Computing, German Cancer Research Center (DKFZ), Heidelberg, Germany
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This code is copied from https://gist.github.com/nlessmann/24d405eaa82abba6676deb6be839266c. All credits go to the
original author (user nlessmann on GitHub)
"""
import numpy as np
import SimpleITK as sitk
def reverse_axes(image):
return np.transpose(image, tuple(reversed(range(image.ndim))))
def read_image(imagefile):
image = sitk.ReadImage(imagefile)
data = reverse_axes(sitk.GetArrayFromImage(image)) # switch from zyx to xyz
header = {
'spacing': image.GetSpacing(),
'origin': image.GetOrigin(),
'direction': image.GetDirection()
}
return data, header
def save_image(img: np.ndarray, header: dict, output_file: str):
"""
CAREFUL you need to restore_original_slice_orientation before saving!
:param img:
:param header:
:return:
"""
# reverse back
img = reverse_axes(img) # switch from zyx to xyz
img_itk = sitk.GetImageFromArray(img)
img_itk.SetSpacing(header['spacing'])
img_itk.SetOrigin(header['origin'])
if not isinstance(header['direction'], tuple):
img_itk.SetDirection(header['direction'].flatten())
else:
img_itk.SetDirection(header['direction'])
sitk.WriteImage(img_itk, output_file)
def swap_flip_dimensions(cosine_matrix, image, header=None):
# Compute swaps and flips
swap = np.argmax(abs(cosine_matrix), axis=0)
flip = np.sum(cosine_matrix, axis=0)
# Apply transformation to image volume
image = np.transpose(image, tuple(swap))
image = image[tuple(slice(None, None, int(f)) for f in flip)]
if header is None:
return image
# Apply transformation to header
header['spacing'] = tuple(header['spacing'][s] for s in swap)
header['direction'] = np.eye(3)
return image, header
def normalize_slice_orientation(image, header):
# Preserve original header so that we can easily transform back
header['original'] = header.copy()
# Compute inverse of cosine (round first because we assume 0/1 values only)
# to determine how the image has to be transposed and flipped for cosine = identity
cosine = np.asarray(header['direction']).reshape(3, 3)
cosine_inv = np.linalg.inv(np.round(cosine))
return swap_flip_dimensions(cosine_inv, image, header)
def restore_original_slice_orientation(mask, header):
# Use original orientation for transformation because we assume the image to be in
# normalized orientation, i.e., identity cosine)
cosine = np.asarray(header['original']['direction']).reshape(3, 3)
cosine_rnd = np.round(cosine)
# Apply transformations to both the image and the mask
return swap_flip_dimensions(cosine_rnd, mask), header['original']