def from_slice(cls, slice_to_copy): slice = cls() if not isinstance(slice_to_copy, Slice): raise ValueError("Input must be of type Slice. Given: %s" % type(slice_to_copy)) # Copy image slice and mask slice.sitk = sitk.Image(slice_to_copy.sitk) slice.itk = sitkh.get_itk_from_sitk_image(slice.sitk) slice.sitk_mask = sitk.Image(slice_to_copy.sitk_mask) slice.itk_mask = sitkh.get_itk_from_sitk_image(slice.sitk_mask) slice._filename = slice_to_copy.get_filename() slice._slice_number = slice_to_copy.get_slice_number() slice._dir_input = slice_to_copy.get_directory() # slice._history_affine_transforms, slice._history_motion_corrections = slice_to_copy.get_registration_history() # Store current affine transform of image slice._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( slice.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of slice, and rigid motion estimates of slice # obtained in the course of the registration/reconstruction process slice._history_affine_transforms, slice._history_motion_corrections = slice_to_copy.get_registration_history( ) return slice
def from_stack(cls, stack_to_copy, filename=None): stack = cls() if not isinstance(stack_to_copy, Stack): raise ValueError("Input must be of type Stack. Given: %s" % type(stack_to_copy)) # Copy image stack and mask stack.sitk = sitk.Image(stack_to_copy.sitk) stack.itk = sitkh.get_itk_from_sitk_image(stack.sitk) stack.sitk_mask = sitk.Image(stack_to_copy.sitk_mask) stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) stack._is_unity_mask = stack_to_copy.is_unity_mask() if filename is None: stack._filename = stack_to_copy.get_filename() else: stack._filename = filename stack._dir = stack_to_copy.get_directory() # Extract all slices and their masks from the stack and store them if # given if stack_to_copy.get_slices() is not None: stack._N_slices = stack_to_copy.get_number_of_slices() stack._slices = [None]*stack._N_slices slices_to_copy = stack_to_copy.get_slices() for i in range(0, stack._N_slices): stack._slices[i] = sl.Slice.from_slice(slices_to_copy[i]) else: stack._N_slices = 0 stack._slices = None return stack
def from_sitk_image(cls, image_sitk, filename="unknown", image_sitk_mask=None, extract_slices=True): stack = cls() stack.sitk = sitk.Image(image_sitk) stack.itk = sitkh.get_itk_from_sitk_image(stack.sitk) stack._filename = filename stack._dir = None # Append masks (if provided) if image_sitk_mask is not None: stack.sitk_mask = image_sitk_mask stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) if sitk.GetArrayFromImage(stack.sitk_mask).prod() == 1: stack._is_unity_mask = True else: stack._is_unity_mask = False else: stack.sitk_mask = stack._generate_identity_mask() stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) stack._is_unity_mask = True # Extract all slices and their masks from the stack and store them if extract_slices: stack._N_slices = stack.sitk.GetSize()[-1] stack._slices = stack._extract_slices() else: stack._N_slices = 0 stack._slices = None return stack
def from_slices(cls, slices, stack_sitk=None, mask_sitk=None): stack = cls() stack._dir = slices[0].get_directory() stack._filename = slices[0].get_filename() if stack_sitk is None: stack.sitk = None stack.itk = None else: stack.sitk = stack_sitk stack.itk = sitkh.get_itk_from_sitk_image(stack.sitk) stack._N_slices = len(slices) stack._slices = slices # Append masks (if provided) if mask_sitk is not None: stack.sitk_mask = mask_sitk stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) stack._is_unity_mask = False else: stack.sitk_mask = stack._generate_identity_mask() stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) stack._is_unity_mask = True return stack
def from_filename(cls, file_path, slice_number, slice_thickness, file_path_mask=None, verbose=False, ): slice = cls() if not ph.file_exists(file_path): raise exceptions.FileNotExistent(file_path) slice._dir_input = os.path.dirname(file_path) slice._filename = os.path.basename(file_path).split(".")[0] slice._slice_number = slice_number slice._slice_thickness = slice_thickness # Append stacks as SimpleITK and ITK Image objects slice.sitk = sitkh.read_nifti_image_sitk(file_path, sitk.sitkFloat64) slice.itk = sitkh.get_itk_from_sitk_image(slice.sitk) # Append masks (if provided) if file_path_mask is None: slice.sitk_mask = slice._generate_identity_mask() if verbose: ph.print_info( "Identity mask created for '%s'." % (file_path)) else: if not ph.file_exists(file_path_mask): raise exceptions.FileNotExistent(file_path_mask) slice.sitk_mask = sitkh.read_nifti_image_sitk( file_path_mask, sitk.sitkUInt8) try: # ensure mask occupies the same physical space slice.sitk_mask.CopyInformation(slice.sitk) except RuntimeError as e: raise IOError( "Given image and its mask do not occupy the same space: %s" % e.message) slice.itk_mask = sitkh.get_itk_from_sitk_image(slice.sitk_mask) # Store current affine transform of image slice._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( slice.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of slice, and motion estimates of slice # obtained in the course of the registration/reconstruction process slice._history_affine_transforms = [] slice._history_affine_transforms.append(slice._affine_transform_sitk) slice._history_motion_corrections = [] slice._history_motion_corrections.append(sitk.Euler3DTransform()) return slice
def from_sitk_image(cls, slice_sitk, slice_number, filename="unknown", slice_sitk_mask=None): slice = cls() # Directory # dir_input = "/".join(filename.split("/")[0:-1]) + "/" # Filename without extension # filename = filename.split("/")[-1:][0].split(".")[0] slice._dir_input = None slice._filename = filename slice._slice_number = slice_number # Append stacks as SimpleITK and ITK Image objects slice.sitk = slice_sitk slice.itk = sitkh.get_itk_from_sitk_image(slice_sitk) # Append masks (if provided) if slice_sitk_mask is not None: slice.sitk_mask = slice_sitk_mask slice.itk_mask = sitkh.get_itk_from_sitk_image(slice_sitk_mask) else: slice.sitk_mask = slice._generate_identity_mask() slice.itk_mask = sitkh.get_itk_from_sitk_image(slice.sitk_mask) # slice._sitk_upsampled = None # HACK (for current Slice-to-Volume Registration) # See class SliceToVolumeRegistration # slice._sitk_upsampled = slice._get_upsampled_isotropic_resolution_slice(slice_sitk) # slice._itk_upsampled = sitkh.get_itk_from_sitk_image(slice._sitk_upsampled) # if slice_sitk_mask is not None: # slice._sitk_mask_upsampled = slice._get_upsampled_isotropic_resolution_slice(slice_sitk_mask) # slice._itk_mask_upsampled = sitkh.get_itk_from_sitk_image(slice._sitk_mask_upsampled) # else: # slice._sitk_mask_upsampled = None # slice._itk_mask_upsampled = None # Store current affine transform of image slice._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( slice.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of slice, and rigid motion estimates of slice # obtained in the course of the registration/reconstruction process slice._history_affine_transforms = [] slice._history_affine_transforms.append(slice._affine_transform_sitk) slice._history_motion_corrections = [] slice._history_motion_corrections.append(sitk.Euler3DTransform()) return slice
def from_filename(cls, file_path, slice_number, file_path_mask=None, verbose=False): slice = cls() if not ph.file_exists(file_path): raise exceptions.FileNotExistent(file_path) slice._dir_input = os.path.dirname(file_path) slice._filename = os.path.basename(file_path).split(".")[0] slice._slice_number = slice_number # Append stacks as SimpleITK and ITK Image objects slice.sitk = sitk.ReadImage(file_path, sitk.sitkFloat64) slice.itk = sitkh.get_itk_from_sitk_image(slice.sitk) # Append masks (if provided) if file_path_mask is None: slice.sitk_mask = slice._generate_identity_mask() if verbose: ph.print_info("Identity mask created for '%s'." % (file_path)) else: if not ph.file_exists(file_path_mask): raise exceptions.FileNotExistent(file_path_mask) slice.sitk_mask = sitk.ReadImage(file_path_mask, sitk.sitkUInt8) slice.itk_mask = sitkh.get_itk_from_sitk_image(slice.sitk_mask) # Store current affine transform of image slice._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( slice.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of slice, and motion estimates of slice # obtained in the course of the registration/reconstruction process slice._history_affine_transforms = [] slice._history_affine_transforms.append(slice._affine_transform_sitk) slice._history_motion_corrections = [] slice._history_motion_corrections.append(sitk.Euler3DTransform()) return slice
def from_stack(cls, stack_to_copy, filename=None): stack = cls() if not isinstance(stack_to_copy, Stack): raise ValueError("Input must be of type Stack. Given: %s" % type(stack_to_copy)) # Copy image stack and mask stack.sitk = sitk.Image(stack_to_copy.sitk) stack.itk = sitkh.get_itk_from_sitk_image(stack.sitk) stack._slice_thickness = stack_to_copy.get_slice_thickness() stack.sitk_mask = sitk.Image(stack_to_copy.sitk_mask) stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) stack._is_unity_mask = stack_to_copy.is_unity_mask() if filename is None: stack._filename = stack_to_copy.get_filename() else: stack._filename = filename stack._dir = stack_to_copy.get_directory() stack._deleted_slices = stack_to_copy.get_deleted_slice_numbers() # Store current affine transform of image stack.set_registration_history( stack_to_copy.get_registration_history()) # Extract all slices and their masks from the stack and store them if # given if stack_to_copy.get_slices() is not None: stack._N_slices = stack_to_copy.get_number_of_slices() stack._slices = [None] * stack._N_slices slices_to_copy = stack_to_copy.get_slices() for j, slice_j in enumerate(slices_to_copy): stack._slices[j] = sl.Slice.from_slice(slice_j) else: stack._N_slices = 0 stack._slices = None return stack
def setUp(self): self.accuracy = 10 # ----------------------------------2D--------------------------------- self.fixed_sitk_2D = sitk.ReadImage( os.path.join(DIR_DATA, "2D_Brain_Target.png"), sitk.sitkFloat64) self.moving_sitk_2D = sitk.ReadImage( os.path.join(DIR_DATA, "2D_Brain_Source.png"), sitk.sitkFloat64) self.fixed_sitk_mask_2D = sitk.ReadImage( os.path.join(DIR_DATA, "2D_Brain_Target_mask.png"), sitk.sitkUInt8) self.moving_sitk_mask_2D = sitk.ReadImage( os.path.join(DIR_DATA, "2D_Brain_Source_mask.png"), sitk.sitkUInt8) self.fixed_itk_2D = sitkh.get_itk_from_sitk_image(self.fixed_sitk_2D) self.moving_itk_2D = sitkh.get_itk_from_sitk_image(self.moving_sitk_2D) self.fixed_itk_mask_2D = sitkh.get_itk_from_sitk_image( self.fixed_sitk_mask_2D) self.moving_itk_mask_2D = sitkh.get_itk_from_sitk_image( self.moving_sitk_mask_2D) # ---------------------------------3D---------------------------------- self.fixed_sitk_3D = sitk.ReadImage( os.path.join(DIR_DATA, "3D_Brain_Source.nii.gz")) self.moving_sitk_3D = sitk.ReadImage( os.path.join(DIR_DATA, "3D_Brain_Target.nii.gz")) self.fixed_itk_3D = sitkh.get_itk_from_sitk_image(self.fixed_sitk_3D) self.moving_itk_3D = sitkh.get_itk_from_sitk_image(self.moving_sitk_3D)
def from_slice_filenames( cls, dir_input, prefix_stack, suffix_mask=None, dic_slice_filenames=None, prefix_slice="_slice", slice_thickness=None, ): stack = cls() if dir_input[-1] is not "/": dir_input += "/" stack._dir = dir_input stack._filename = prefix_stack # Get 3D images stack.sitk = sitkh.read_nifti_image_sitk( dir_input + prefix_stack + ".nii.gz", sitk.sitkFloat64) stack.itk = sitkh.get_itk_from_sitk_image(stack.sitk) # Set slice thickness of acquisition if slice_thickness is None: stack._slice_thickness = stack.sitk.GetSpacing()[-1] else: stack._slice_thickness = slice_thickness # Append masks (either provided or binary mask) if suffix_mask is not None and \ os.path.isfile(dir_input + prefix_stack + suffix_mask + ".nii.gz"): stack.sitk_mask = sitkh.read_nifti_image_sitk( dir_input + prefix_stack + suffix_mask + ".nii.gz", sitk.sitkUInt8) stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) stack._is_unity_mask = False else: stack.sitk_mask = stack._generate_identity_mask() stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) stack._is_unity_mask = True # Get slices if dic_slice_filenames is None: stack._N_slices = stack.sitk.GetDepth() stack._slices = [None] * stack._N_slices # Append slices as Slice objects for i in range(0, stack._N_slices): path_to_slice = os.path.join( dir_input, prefix_stack + prefix_slice + str(i) + ".nii.gz") path_to_slice_mask = os.path.join( dir_input, prefix_stack + prefix_slice + str(i) + suffix_mask + ".nii.gz") if ph.file_exists(path_to_slice_mask): stack._slices[i] = sl.Slice.from_filename( file_path=path_to_slice, slice_number=i, file_path_mask=path_to_slice_mask) else: stack._slices[i] = sl.Slice.from_filename( file_path=path_to_slice, slice_number=i) else: slice_numbers = sorted(dic_slice_filenames.keys()) stack._N_slices = len(slice_numbers) stack._slices = [None] * stack._N_slices for i, slice_number in enumerate(slice_numbers): path_to_slice = os.path.join( dir_input, dic_slice_filenames[slice_number] + ".nii.gz") path_to_slice_mask = os.path.join( dir_input, dic_slice_filenames[slice_number] + suffix_mask + ".nii.gz") if ph.file_exists(path_to_slice_mask): stack._slices[i] = sl.Slice.from_filename( file_path=path_to_slice, slice_number=slice_number, file_path_mask=path_to_slice_mask, slice_thickness=stack.get_slice_thickness(), ) else: stack._slices[i] = sl.Slice.from_filename( file_path=path_to_slice, slice_number=slice_number, slice_thickness=stack.get_slice_thickness(), ) return stack
def from_sitk_image( cls, slice_sitk, slice_number, slice_thickness, filename="unknown", slice_sitk_mask=None, ): slice = cls() # Directory # dir_input = "/".join(filename.split("/")[0:-1]) + "/" # Filename without extension # filename = filename.split("/")[-1:][0].split(".")[0] slice._dir_input = None slice._filename = filename slice._slice_number = slice_number slice._slice_thickness = slice_thickness # Explicit cast (+ creation of other image instance) slice.sitk = sitk.Cast(slice_sitk, sitk.sitkFloat64) slice.itk = sitkh.get_itk_from_sitk_image(slice.sitk) # Append masks (if provided) if slice_sitk_mask is not None: slice.sitk_mask = sitk.Cast(slice_sitk_mask, sitk.sitkUInt8) try: # ensure mask occupies the same physical space slice.sitk_mask.CopyInformation(slice.sitk) except RuntimeError as e: raise IOError( "Given image and its mask do not occupy the same space: %s" % e.message) slice.itk_mask = sitkh.get_itk_from_sitk_image(slice.sitk_mask) else: slice.sitk_mask = slice._generate_identity_mask() slice.itk_mask = sitkh.get_itk_from_sitk_image(slice.sitk_mask) # slice._sitk_upsampled = None # HACK (for current Slice-to-Volume Registration) # See class SliceToVolumeRegistration # slice._sitk_upsampled = slice._get_upsampled_isotropic_resolution_slice(slice_sitk) # slice._itk_upsampled = # sitkh.get_itk_from_sitk_image(slice._sitk_upsampled) # if slice_sitk_mask is not None: # slice._sitk_mask_upsampled = slice._get_upsampled_isotropic_resolution_slice(slice_sitk_mask) # slice._itk_mask_upsampled = sitkh.get_itk_from_sitk_image(slice._sitk_mask_upsampled) # else: # slice._sitk_mask_upsampled = None # slice._itk_mask_upsampled = None # Store current affine transform of image slice._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( slice.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of slice, and rigid motion estimates of slice # obtained in the course of the registration/reconstruction process slice._history_affine_transforms = [] slice._history_affine_transforms.append(slice._affine_transform_sitk) slice._history_motion_corrections = [] slice._history_motion_corrections.append(sitk.Euler3DTransform()) return slice
def from_filename(cls, file_path, file_path_mask=None, extract_slices=True, verbose=False): stack = cls() if not ph.file_exists(file_path): raise exceptions.FileNotExistent(file_path) path_to_directory = os.path.dirname(file_path) # Strip extension from filename and remove potentially included "." filename = [re.sub("." + ext, "", os.path.basename(file_path)) for ext in ALLOWED_EXTENSIONS if file_path.endswith(ext)][0] # filename = filename.replace(".", "p") stack._dir = os.path.dirname(file_path) stack._filename = filename # Append stacks as SimpleITK and ITK Image objects stack.sitk = sitk.ReadImage(file_path, sitk.sitkFloat64) stack.itk = sitkh.get_itk_from_sitk_image(stack.sitk) # Append masks (either provided or binary mask) if file_path_mask is None: stack.sitk_mask = stack._generate_identity_mask() if verbose: ph.print_info( "Identity mask created for '%s'." % (file_path)) else: if not ph.file_exists(file_path_mask): raise exceptions.FileNotExistent(file_path_mask) stack.sitk_mask = sitk.ReadImage(file_path_mask, sitk.sitkUInt8) stack._is_unity_mask = False # Append itk object stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) # Extract all slices and their masks from the stack and store them if extract_slices: dimenson = stack.sitk.GetDimension() if dimenson == 3: stack._N_slices = stack.sitk.GetSize()[-1] stack._slices = stack._extract_slices() elif dimenson == 2: stack._N_slices = 1 stack._slices = [stack.sitk[:, :]] else: stack._N_slices = 0 stack._slices = None if verbose: ph.print_info( "Stack (image + mask) associated to '%s' successfully read." % (file_path)) return stack
def from_filename( cls, file_path, file_path_mask=None, extract_slices=True, verbose=False, slice_thickness=None, ): stack = cls() if not ph.file_exists(file_path): raise exceptions.FileNotExistent(file_path) path_to_directory = os.path.dirname(file_path) # Strip extension from filename and remove potentially included "." filename = [ re.sub("." + ext, "", os.path.basename(file_path)) for ext in ALLOWED_EXTENSIONS if file_path.endswith(ext) ][0] # filename = filename.replace(".", "p") stack._dir = os.path.dirname(file_path) stack._filename = filename # Append stacks as SimpleITK and ITK Image objects stack.sitk = sitkh.read_nifti_image_sitk(file_path, sitk.sitkFloat64) stack.itk = sitkh.get_itk_from_sitk_image(stack.sitk) # Set slice thickness of acquisition if slice_thickness is None: stack._slice_thickness = stack.sitk.GetSpacing()[-1] else: stack._slice_thickness = slice_thickness # Append masks (either provided or binary mask) if file_path_mask is None: stack.sitk_mask = stack._generate_identity_mask() if verbose: ph.print_info("Identity mask created for '%s'." % (file_path)) else: if not ph.file_exists(file_path_mask): raise exceptions.FileNotExistent(file_path_mask) stack.sitk_mask = sitkh.read_nifti_image_sitk( file_path_mask, sitk.sitkUInt8) try: # ensure masks occupy same physical space stack.sitk_mask.CopyInformation(stack.sitk) except RuntimeError as e: raise IOError( "Given image and its mask do not occupy the same space: %s" % e.message) stack._is_unity_mask = False # Append itk object stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) # Store current affine transform of image stack._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( stack.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of stack, and motion estimates of stack # obtained in the course of the registration/reconstruction process stack._history_affine_transforms = [] stack._history_affine_transforms.append(stack._affine_transform_sitk) stack._history_motion_corrections = [] stack._history_motion_corrections.append(sitk.Euler3DTransform()) # Extract all slices and their masks from the stack and store them if extract_slices: dimenson = stack.sitk.GetDimension() if dimenson == 3: stack._N_slices = stack.sitk.GetSize()[-1] stack._slices = stack._extract_slices( slice_thickness=stack.get_slice_thickness()) elif dimenson == 2: stack._N_slices = 1 stack._slices = [stack.sitk[:, :]] else: stack._N_slices = 0 stack._slices = None if verbose: ph.print_info( "Stack (image + mask) associated to '%s' successfully read." % (file_path)) return stack
def _run_discrete_shepard_reconstruction(self): shape = sitk.GetArrayFromImage(self._HR_volume.sitk).shape helper_N_nda = np.zeros(shape) helper_D_nda = np.zeros(shape) default_pixel_value = 0.0 for i in range(0, self._N_stacks): if self._verbose: ph.print_info("Stack %s/%s" % (i + 1, self._N_stacks)) stack = self._stacks[i] slices = stack.get_slices() N_slices = stack.get_number_of_slices() # for j in range(10, 11): for j in range(0, N_slices): # print("\t\tSlice %s/%s" %(j,N_slices-1)) slice = slices[j] slice_sitk = self._get_slice[(bool(self._use_masks), bool(self._sda_mask))](slice) # Add intensity offset so that a "zero" intensity can be # identified as contribution of image slice (line 353/356) slice_sitk += 1 # Nearest neighbour resampling of slice to target space (HR # volume) slice_resampled_sitk = sitk.Resample( slice_sitk, self._HR_volume.sitk, sitk.Euler3DTransform(), sitk.sitkNearestNeighbor, default_pixel_value, self._HR_volume.sitk.GetPixelIDValue()) # sitkh.show_sitk_image(slice_resampled_sitk) # Extract array of pixel intensities nda_slice = sitk.GetArrayFromImage(slice_resampled_sitk) # Get voxels in HR volume space which are struck by the slice ind_nonzero = nda_slice > 0 # update numerator (correct previous intensity offset) helper_N_nda[ind_nonzero] += nda_slice[ind_nonzero] - 1 # update denominator helper_D_nda[ind_nonzero] += 1 # test = sitk.GetImageFromArray(helper_N_nda) # sitkh.show_sitk_image(test,title="N") # test = sitk.GetImageFromArray(helper_D_nda) # sitkh.show_sitk_image(test,title="D") # print("helper_N_nda: (min, max) = (%s, %s)" %(np.min(helper_N_nda), np.max(helper_N_nda))) # print("helper_D_nda: (min, max) = (%s, %s)" %(np.min(helper_D_nda), np.max(helper_D_nda))) # TODO: Set zero entries to one; Otherwise results are very weird!? helper_D_nda[helper_D_nda == 0] = 1 # Create itk-images with correct header data pixel_type = itk.D dimension = 3 image_type = itk.Image[pixel_type, dimension] itk2np = itk.PyBuffer[image_type] helper_N = itk2np.GetImageFromArray(helper_N_nda) helper_D = itk2np.GetImageFromArray(helper_D_nda) helper_N.SetSpacing(self._HR_volume.sitk.GetSpacing()) helper_N.SetDirection( sitkh.get_itk_direction_from_sitk_image(self._HR_volume.sitk)) helper_N.SetOrigin(self._HR_volume.sitk.GetOrigin()) helper_D.SetSpacing(self._HR_volume.sitk.GetSpacing()) helper_D.SetDirection( sitkh.get_itk_direction_from_sitk_image(self._HR_volume.sitk)) helper_D.SetOrigin(self._HR_volume.sitk.GetOrigin()) # Apply Recursive Gaussian YVV filter gaussian = itk.SmoothingRecursiveYvvGaussianImageFilter[ image_type, image_type].New() # YVV-based Filter # gaussian = itk.SmoothingRecursiveGaussianImageFilter[image_type, # image_type].New() # Deriche-based Filter gaussian.SetSigmaArray(self._sigma_array) gaussian.SetInput(helper_N) gaussian.Update() HR_volume_update_N = gaussian.GetOutput() HR_volume_update_N.DisconnectPipeline() gaussian.SetInput(helper_D) gaussian.Update() HR_volume_update_D = gaussian.GetOutput() HR_volume_update_D.DisconnectPipeline() # Convert numerator and denominator back to data array nda_N = itk2np.GetArrayFromImage(HR_volume_update_N) nda_D = itk2np.GetArrayFromImage(HR_volume_update_D) # Compute data array of HR volume: # nda_D[nda_D==0]=1 nda = nda_N / nda_D.astype(float) # Update HR volume image file within Stack-object HR_volume HR_volume_update = sitk.GetImageFromArray(nda) HR_volume_update.CopyInformation(self._HR_volume.sitk) if not self._sda_mask: self._HR_volume.sitk = HR_volume_update self._HR_volume.itk = sitkh.get_itk_from_sitk_image( HR_volume_update) else: # Approximate uint8 mask from float SDA outcome mask_estimator = bm.BinaryMaskFromMaskSRREstimator( HR_volume_update) mask_estimator.run() HR_volume_update = mask_estimator.get_mask_sitk() self._HR_volume.sitk_mask = HR_volume_update self._HR_volume.itk_mask = sitkh.get_itk_from_sitk_image( HR_volume_update)
def from_sitk_image( cls, image_sitk, slice_thickness, filename="unknown", image_sitk_mask=None, extract_slices=True, slice_numbers=None, ): stack = cls() # Explicit cast (+ creation of other image instance) stack.sitk = sitk.Cast(image_sitk, sitk.sitkFloat64) stack.itk = sitkh.get_itk_from_sitk_image(stack.sitk) # Set slice thickness of acquisition if not ph.is_float(slice_thickness): raise ValueError("Slice thickness must be of type float") stack._slice_thickness = float(slice_thickness) stack._filename = filename stack._dir = None # Append masks (if provided) if image_sitk_mask is not None: stack.sitk_mask = sitk.Cast(image_sitk_mask, sitk.sitkUInt8) try: # ensure mask occupies the same physical space stack.sitk_mask.CopyInformation(stack.sitk) except RuntimeError as e: raise IOError( "Given image and its mask do not occupy the same space: %s" % e.message) stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) if sitk.GetArrayFromImage(stack.sitk_mask).prod() == 1: stack._is_unity_mask = True else: stack._is_unity_mask = False else: stack.sitk_mask = stack._generate_identity_mask() stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) stack._is_unity_mask = True # Extract all slices and their masks from the stack and store them if extract_slices: stack._N_slices = stack.sitk.GetSize()[-1] stack._slices = stack._extract_slices( slice_numbers=slice_numbers, slice_thickness=slice_thickness, ) else: stack._N_slices = 0 stack._slices = None # Store current affine transform of image stack._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( stack.sitk) stack._history_affine_transforms = [] stack._history_affine_transforms.append(stack._affine_transform_sitk) stack._history_motion_corrections = [] stack._history_motion_corrections.append(sitk.Euler3DTransform()) return stack
def from_slice_filenames( cls, dir_input, prefix_stack, suffix_mask=None, dic_slice_filenames=None, prefix_slice="_slice", slice_thickness=None, ): stack = cls() if dir_input[-1] is not "/": dir_input += "/" stack._dir = dir_input stack._filename = prefix_stack # Get 3D images stack.sitk = sitkh.read_nifti_image_sitk( dir_input + prefix_stack + ".nii.gz", sitk.sitkFloat64) stack.itk = sitkh.get_itk_from_sitk_image(stack.sitk) # Store current affine transform of image stack._affine_transform_sitk = sitkh.get_sitk_affine_transform_from_sitk_image( stack.sitk) # Prepare history of affine transforms, i.e. encoded spatial # position+orientation of stack, and motion estimates of stack # obtained in the course of the registration/reconstruction process stack._history_affine_transforms = [] stack._history_affine_transforms.append(stack._affine_transform_sitk) stack._history_motion_corrections = [] stack._history_motion_corrections.append(sitk.Euler3DTransform()) # Set slice thickness of acquisition if slice_thickness is None: stack._slice_thickness = float(stack.sitk.GetSpacing()[-1]) else: stack._slice_thickness = float(slice_thickness) # Append masks (either provided or binary mask) if suffix_mask is not None and \ os.path.isfile(dir_input + prefix_stack + suffix_mask + ".nii.gz"): stack.sitk_mask = sitkh.read_nifti_image_sitk( dir_input + prefix_stack + suffix_mask + ".nii.gz", sitk.sitkUInt8) stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) stack._is_unity_mask = False else: stack.sitk_mask = stack._generate_identity_mask() stack.itk_mask = sitkh.get_itk_from_sitk_image(stack.sitk_mask) stack._is_unity_mask = True # Get slices if dic_slice_filenames is None: stack._N_slices = stack.sitk.GetDepth() stack._slices = [None] * stack._N_slices # Append slices as Slice objects for i in range(0, stack._N_slices): path_to_slice = os.path.join( dir_input, prefix_stack + prefix_slice + str(i) + ".nii.gz") path_to_slice_mask = os.path.join( dir_input, prefix_stack + prefix_slice + str(i) + suffix_mask + ".nii.gz") if ph.file_exists(path_to_slice_mask): stack._slices[i] = sl.Slice.from_filename( file_path=path_to_slice, slice_number=i, file_path_mask=path_to_slice_mask) else: stack._slices[i] = sl.Slice.from_filename( file_path=path_to_slice, slice_number=i) else: slice_numbers = sorted(dic_slice_filenames.keys()) stack._N_slices = len(slice_numbers) stack._slices = [None] * stack._N_slices for i, slice_number in enumerate(slice_numbers): path_to_slice = os.path.join( dir_input, dic_slice_filenames[slice_number] + ".nii.gz") path_to_slice_mask = os.path.join( dir_input, dic_slice_filenames[slice_number] + suffix_mask + ".nii.gz") if ph.file_exists(path_to_slice_mask): stack._slices[i] = sl.Slice.from_filename( file_path=path_to_slice, slice_number=slice_number, file_path_mask=path_to_slice_mask, slice_thickness=stack.get_slice_thickness(), ) else: stack._slices[i] = sl.Slice.from_filename( file_path=path_to_slice, slice_number=slice_number, slice_thickness=stack.get_slice_thickness(), ) return stack
def _run_discrete_shepard_based_on_Deriche_reconstruction(self): shape = sitk.GetArrayFromImage(self._HR_volume.sitk).shape helper_N_nda = np.zeros(shape) helper_D_nda = np.zeros(shape) default_pixel_value = 0.0 for i in range(0, self._N_stacks): if self._verbose: ph.print_info("Stack %s/%s" % (i + 1, self._N_stacks)) stack = self._stacks[i] slices = stack.get_slices() N_slices = stack.get_number_of_slices() for j in range(0, N_slices): slice = slices[j] slice_sitk = self._get_slice[(bool(self._use_masks), bool(self._sda_mask))](slice) # Nearest neighbour resampling of slice to target space (HR # volume) slice_resampled_sitk = sitk.Resample( slice_sitk, self._HR_volume.sitk, sitk.Euler3DTransform(), sitk.sitkNearestNeighbor, default_pixel_value, self._HR_volume.sitk.GetPixelIDValue()) # Extract array of pixel intensities nda_slice = sitk.GetArrayFromImage(slice_resampled_sitk) # Look for indices which are stroke by the slice in the # isotropic grid ind_nonzero = nda_slice > 0 # update arrays of numerator and denominator helper_N_nda[ind_nonzero] += nda_slice[ind_nonzero] helper_D_nda[ind_nonzero] += 1 # print("helper_N_nda: (min, max) = (%s, %s)" %(np.min(helper_N_nda), np.max(helper_N_nda))) # print("helper_D_nda: (min, max) = (%s, %s)" %(np.min(helper_D_nda), np.max(helper_D_nda))) # TODO: Set zero entries to one; Otherwise results are very weird!? helper_D_nda[helper_D_nda == 0] = 1 # Create sitk-images with correct header data helper_N = sitk.GetImageFromArray(helper_N_nda) helper_D = sitk.GetImageFromArray(helper_D_nda) helper_N.CopyInformation(self._HR_volume.sitk) helper_D.CopyInformation(self._HR_volume.sitk) # Apply recursive Gaussian smoothing gaussian = sitk.SmoothingRecursiveGaussianImageFilter() gaussian.SetSigma(self._sigma_array[1]) HR_volume_update_N = gaussian.Execute(helper_N) HR_volume_update_D = gaussian.Execute(helper_D) # ## Avoid undefined division by zero # """ # HACK start # """ # ## HACK for denominator # nda = sitk.GetArrayFromImage(HR_volume_update_D) # ind_min = np.unravel_index(np.argmin(nda), nda.shape) # # print(nda[nda<0]) # # print(nda[ind_min]) # eps = 1e-8 # # nda[nda<=eps]=1 # print("denominator min = %s" % np.min(nda)) # HR_volume_update_D = sitk.GetImageFromArray(nda) # HR_volume_update_D.CopyInformation(self._HR_volume.sitk) # ## HACK for numerator given that some intensities are negative!? # nda = sitk.GetArrayFromImage(HR_volume_update_N) # ind_min = np.unravel_index(np.argmin(nda), nda.shape) # # nda[nda<=eps]=0 # # print(nda[nda<0]) # print("numerator min = %s" % np.min(nda)) # """ # HACK end # """ # Compute HR volume based on scattered data approximation with correct # header (might be redundant): HR_volume_update = HR_volume_update_N / HR_volume_update_D HR_volume_update.CopyInformation(self._HR_volume.sitk) if not self._sda_mask: self._HR_volume.sitk = HR_volume_update self._HR_volume.itk = sitkh.get_itk_from_sitk_image( HR_volume_update) else: # Approximate uint8 mask from float SDA outcome mask_estimator = bm.BinaryMaskFromMaskSRREstimator( HR_volume_update) mask_estimator.run() HR_volume_update = mask_estimator.get_mask_sitk() self._HR_volume.sitk_mask = HR_volume_update self._HR_volume.itk_mask = sitkh.get_itk_from_sitk_image( HR_volume_update) """ Additional info """ if self._verbose: nda = sitk.GetArrayFromImage(HR_volume_update) print("Minimum of data array = %s" % np.min(nda))