def compute_slice_projections(self): linear_operators = lin_op.LinearOperators() self._slice_projections = [None] * len(self._stacks) for i_stack, stack in enumerate(self._stacks): slices = stack.get_slices() N_slices = self._get_original_number_of_slices(stack) self._slice_projections[i_stack] = [self._init_value] * N_slices if self._verbose: ph.print_info("Stack %d/%d: Compute slice projections ... " % (i_stack + 1, len(self._stacks)), newline=False) # Compute slice projections based on assumed slice acquisition # protocol for slice in slices: i_slice = slice.get_slice_number() self._slice_projections[i_stack][i_slice] = linear_operators.A( self._reference, slice) if self._verbose: print("done")
def test_forward_operator_stack(self): data_reader = dr.MultipleImagesReader(self.paths_to_filenames, suffix_mask=self.suffix_mask) data_reader.read_data() stacks = data_reader.get_data() stack = stacks[0] reconstruction = st.Stack.from_filename(self.path_to_recon, self.path_to_recon_mask) linear_operators = lin_op.LinearOperators() simulated_stack = linear_operators.A(reconstruction, stack, interpolator_mask="Linear") simulated_stack.set_filename(stack.get_filename() + "_sim") # sitkh.show_stacks([stack, simulated_stack]) # simulated_stack.show(1) # reconstruction.show(1) # stack.show(1) filename_reference = "IC_N4ITK_HASTE_exam_3.5mm_800ms_3_simulated" reference_simulated_stack = st.Stack.from_filename( os.path.join(self.dir_data, "result-comparison", filename_reference + ".nii.gz"), os.path.join(self.dir_data, "result-comparison", filename_reference + self.suffix_mask + ".nii.gz")) # Error simulated stack difference_sitk = simulated_stack.sitk - \ reference_simulated_stack.sitk error = np.linalg.norm(sitk.GetArrayFromImage(difference_sitk)) self.assertAlmostEqual(error, 0, places=self.precision) # Error propagated mask difference_sitk = simulated_stack.sitk_mask - \ reference_simulated_stack.sitk_mask error = np.linalg.norm(sitk.GetArrayFromImage(difference_sitk)) self.assertAlmostEqual(error, 0, places=self.precision)
def test_forward_operator_stack(self): stack = st.Stack.from_filename(self.path_to_file) reconstruction = st.Stack.from_filename(self.path_to_recon, self.path_to_recon_mask) linear_operators = lin_op.LinearOperators() simulated_stack = linear_operators.A(reconstruction, stack, interpolator_mask="Linear") simulated_stack.set_filename(stack.get_filename() + "_sim") # sitkh.show_stacks( # [stack, simulated_stack], segmentation=simulated_stack) filename_reference = os.path.join(self.dir_data, "recon_projections", "stack", "%s_sim.nii.gz" % self.filename) filename_reference_mask = os.path.join( self.dir_data, "recon_projections", "stack", "%s_sim%s.nii.gz" % (self.filename, self.suffix_mask)) reference_simulated_stack = st.Stack.from_filename( filename_reference, filename_reference_mask) # Error simulated stack difference_sitk = simulated_stack.sitk - \ reference_simulated_stack.sitk error = np.linalg.norm(sitk.GetArrayFromImage(difference_sitk)) self.assertAlmostEqual(error, 0, places=self.precision) # Error propagated mask difference_sitk = simulated_stack.sitk_mask - \ reference_simulated_stack.sitk_mask error = np.linalg.norm(sitk.GetArrayFromImage(difference_sitk)) self.assertAlmostEqual(error, 0, places=self.precision)
def main(): input_parser = InputArgparser( description="Simulate stacks from obtained reconstruction. " "Script simulates/projects the slices at estimated positions " "within reconstructed volume. Ideally, if motion correction was " "correct, the resulting stack of such obtained projected slices, " "corresponds to the originally acquired (motion corrupted) data.", ) input_parser.add_filenames(required=True) input_parser.add_filenames_masks() input_parser.add_dir_input_mc(required=True) input_parser.add_reconstruction(required=True) input_parser.add_dir_output(required=True) input_parser.add_suffix_mask(default="_mask") input_parser.add_prefix_output(default="Simulated_") input_parser.add_option( option_string="--copy-data", type=int, help="Turn on/off copying of original data (including masks) to " "output folder.", default=0) input_parser.add_option( option_string="--reconstruction-mask", type=str, help="If given, reconstruction image mask is propagated to " "simulated stack(s) of slices as well", default=None) input_parser.add_interpolator( option_string="--interpolator-mask", help="Choose the interpolator type to propagate the reconstruction " "mask (%s)." % (INTERPOLATOR_TYPES), default="NearestNeighbor") input_parser.add_log_config(default=0) input_parser.add_verbose(default=0) input_parser.add_slice_thicknesses(default=None) args = input_parser.parse_args() input_parser.print_arguments(args) if args.interpolator_mask not in ALLOWED_INTERPOLATORS: raise IOError( "Unknown interpolator provided. Possible choices are %s" % ( INTERPOLATOR_TYPES)) if args.log_config: input_parser.log_config(os.path.abspath(__file__)) # Read motion corrected data data_reader = dr.MultipleImagesReader( file_paths=args.filenames, file_paths_masks=args.filenames_masks, suffix_mask=args.suffix_mask, dir_motion_correction=args.dir_input_mc, stacks_slice_thicknesses=args.slice_thicknesses, ) data_reader.read_data() stacks = data_reader.get_data() reconstruction = st.Stack.from_filename( args.reconstruction, args.reconstruction_mask, extract_slices=False) linear_operators = lin_op.LinearOperators() for i, stack in enumerate(stacks): # initialize image data array(s) nda = np.zeros_like(sitk.GetArrayFromImage(stack.sitk)) nda[:] = np.nan if args.reconstruction_mask: nda_mask = np.zeros_like(sitk.GetArrayFromImage(stack.sitk_mask)) slices = stack.get_slices() kept_indices = [s.get_slice_number() for s in slices] # Fill stack information "as if slice was acquired consecutively" # Therefore, simulated stack slices correspond to acquired slices # (in case motion correction was correct) for j in range(nda.shape[0]): if j in kept_indices: index = kept_indices.index(j) simulated_slice = linear_operators.A( reconstruction, slices[index], interpolator_mask=args.interpolator_mask ) nda[j, :, :] = sitk.GetArrayFromImage(simulated_slice.sitk) if args.reconstruction_mask: nda_mask[j, :, :] = sitk.GetArrayFromImage( simulated_slice.sitk_mask) # Create nifti image with same image header as original stack simulated_stack_sitk = sitk.GetImageFromArray(nda) simulated_stack_sitk.CopyInformation(stack.sitk) if args.reconstruction_mask: simulated_stack_sitk_mask = sitk.GetImageFromArray(nda_mask) simulated_stack_sitk_mask.CopyInformation(stack.sitk_mask) else: simulated_stack_sitk_mask = None simulated_stack = st.Stack.from_sitk_image( image_sitk=simulated_stack_sitk, image_sitk_mask=simulated_stack_sitk_mask, filename=args.prefix_output + stack.get_filename(), extract_slices=False, slice_thickness=stack.get_slice_thickness(), ) if args.verbose: sitkh.show_stacks([ stack, simulated_stack], segmentation=stack) simulated_stack.write( args.dir_output, write_mask=False, write_slices=False, suffix_mask=args.suffix_mask) if args.copy_data: stack.write( args.dir_output, write_mask=True, write_slices=False, suffix_mask="_mask") return 0
def __init__( self, stacks, reconstruction, alpha_cut, alpha, iter_max, minimizer, x_scale, data_loss, data_loss_scale, huber_gamma, deconvolution_mode, predefined_covariance, verbose, image_type=itk.Image.D3, use_masks=True, ): # Initialize variables self._stacks = stacks self._reconstruction = reconstruction # Cut-off distance for Gaussian blurring filter self._alpha_cut = alpha_cut self._deconvolution_mode = deconvolution_mode self._predefined_covariance = predefined_covariance self._linear_operators = lin_op.LinearOperators( deconvolution_mode=self._deconvolution_mode, predefined_covariance=self._predefined_covariance, alpha_cut=self._alpha_cut, image_type=image_type) # Settings for solver self._alpha = alpha self._iter_max = iter_max self._use_masks = use_masks self._minimizer = minimizer self._data_loss = data_loss self._data_loss_scale = data_loss_scale if x_scale == "max": self._x_scale = sitk.GetArrayFromImage(reconstruction.sitk).max() # Avoid zero in case zero-image is given if self._x_scale == 0: self._x_scale = 1 else: self._x_scale = x_scale self._huber_gamma = huber_gamma self._verbose = verbose # Allocate variables containing information about statistics of # reconstruction self._computational_time = None self._residual_ell2 = None self._residual_prior = None # Create PyBuffer object for conversion between NumPy arrays and ITK # images self._itk2np = itk.PyBuffer[image_type] # -----------------------------Set helpers----------------------------- self._N_stacks = len(self._stacks) # Compute total amount of pixels for all slices self._N_total_slice_voxels = 0 for i in range(0, self._N_stacks): N_stack_voxels = np.array(self._stacks[i].sitk.GetSize()).prod() self._N_total_slice_voxels += N_stack_voxels # Extract information ready to use for itk image conversion operations self._reconstruction_shape = sitk.GetArrayFromImage( self._reconstruction.sitk).shape # Compute total amount of voxels of x: self._N_voxels_recon = np.array( self._reconstruction.sitk.GetSize()).prod()