import numpy as np import SimpleITK as sitk channels = [ "background", "spleen", "right_kidney", "left_kidney", "gallbladder", "liver", "stomach", "pancreas", "right_adrenal_gland", "left_adrenal_gland", "left_lung", "right_lung", "heart", "aorta", "inferior_vena_cava", "portal_vein_and_splenic_vein", "left_iliac_artery", "right_iliac_artery", "left_iliac_vena", "right_iliac_vena", "esophagus", "small_bowel", "duodenum", "colon", "urinary_bladder", "spine", "sacrum", "left_hip", "right_hip", "left_femur", "right_femur", "left_autochthonous_muscle", "right_autochthonous_muscle", "left_iliopsoas_muscle", "right_iliopsoas_muscle", "left_gluteus_maximus", "right_gluteus_maximus", "left_gluteus_medius", "right_gluteus_medius", "left_gluteus_minimus", "right_gluteus_minimus", ] def make_isotropic(image, interpolator=sitk.sitkLinear, spacing=None): """ Many file formats (e.g. jpg, png,...) expect the pixels to be isotropic, same spacing for all axes. Saving non-isotropic data in these formats will result in distorted images. This function makes an image isotropic via resampling, if needed. Args: image (SimpleITK.Image): Input image. interpolator: By default the function uses a linear interpolator. For label images one should use the sitkNearestNeighbor interpolator so as not to introduce non-existant labels. spacing (float): Desired spacing. If none given then use the smallest spacing from the original image. Returns: SimpleITK.Image with isotropic spacing which occupies the same region in space as the input image. """ original_spacing = image.GetSpacing() # Image is already isotropic, just return a copy. if all(spc == original_spacing[0] for spc in original_spacing): return sitk.Image(image) # Make image isotropic via resampling. original_size = image.GetSize() if spacing is None: spacing = min(original_spacing) new_spacing = [spacing] * image.GetDimension() new_size = [int(round(osz * ospc / spacing)) for osz, ospc in zip(original_size, original_spacing)] return sitk.Resample( image, new_size, sitk.Transform(), interpolator, image.GetOrigin(), new_spacing, image.GetDirection(), 0, # default pixel value image.GetPixelID(), ) def label_mapper(seg): labels = [] for _class in np.unique(seg): if _class == 0: continue labels.append((seg == _class, channels[_class])) return labels def sitk2numpy(img, normalize=False): img = sitk.DICOMOrient(img, "LPS") # img = make_isotropic(img) img = sitk.GetArrayFromImage(img) if normalize: minval, maxval = np.min(img), np.max(img) img = ((img - minval) / (maxval - minval)).clip(0, 1) * 255 img = img.astype(np.uint8) return img def read_image(path, normalize=False): img = sitk.ReadImage(path) return sitk2numpy(img, normalize) def display(image, seg=None, _slice=50): # Image if image is None or (isinstance(image, list) and len(image) == 0): return None if isinstance(image, list): image = image[-1] x = int(_slice * (image.shape[0] / 100)) image = image[x, :, :] # Segmentation if seg is None or (isinstance(seg, list) and len(seg) == 0): seg = [] else: if isinstance(seg, list): seg = seg[-1] seg = label_mapper(seg[x, :, :]) return image, seg def read_and_display(path, image_state, seg_state): image_state.clear() seg_state.clear() if path is not None: image = read_image(path, normalize=True) image_state.append(image) return display(image), image_state, seg_state else: return None, image_state, seg_state