def full(images: Images, cors: List[ScalarCoR], recon_params: ReconstructionParameters, progress: Optional[Progress] = None) -> Images: progress = Progress.ensure_instance(progress, num_steps=images.height) output_shape = (images.num_sinograms, images.width, images.width) output_images: Images = Images.create_empty_images( output_shape, images.dtype, images.metadata) output_images.record_operation('AstraRecon.full', 'Reconstruction', **recon_params.to_dict()) # FIXME multiple GPU support - just starting up a Pool doesn't seem to work # the GPUs can't initialise the memory properly. Not sure why # num_gpus = AstraRecon._count_gpus() # LOG.info(f"Running with {num_gpus} GPUs") # partial = ptsm.create_partial(AstraRecon.single, ptsm.fwd_gpu_recon, # num_gpus=num_gpus, cors=cors, # proj_angles=proj_angles, recon_params=recon_params) # ptsm.execute(images.sinograms, output_images.data, partial, num_gpus, progress=progress) proj_angles = images.projection_angles() for i in range(images.height): output_images.data[i] = AstraRecon.single_sino( images.sino(i), cors[i], proj_angles, recon_params) progress.update(1, "Reconstructed slice") return output_images
def find_cor(images: Images, slice_idx: int, start_cor: float, recon_params: ReconstructionParameters) -> float: return tomopy.find_center(images.sinograms, images.projection_angles( recon_params.max_projection_angle).value, ind=slice_idx, init=start_cor, sinogram_order=True)
def __init__(self, images: Images, slice_idx: int, initial_cor: ScalarCoR, recon_params: ReconstructionParameters): self.image_width = images.width self.sino = images.sino(slice_idx) # Initial parameters self.centre_cor = initial_cor.value self.cor_step = 50 # Cache projection angles self.proj_angles = images.projection_angles() self.recon_params = recon_params self.reconstructor = get_reconstructor_for(recon_params.algorithm)
def full(images: Images, cors: List[ScalarCoR], recon_params: ReconstructionParameters, progress: Optional[Progress] = None) -> Images: progress = Progress.ensure_instance(progress, num_steps=images.height) output_shape = (images.num_sinograms, images.width, images.width) output_images: Images = Images.create_empty_images( output_shape, images.dtype, images.metadata) output_images.record_operation('AstraRecon.full', 'Reconstruction', **recon_params.to_dict()) proj_angles = images.projection_angles( recon_params.max_projection_angle) for i in range(images.height): output_images.data[i] = AstraRecon.single_sino( images.sino(i), cors[i], proj_angles, recon_params) progress.update(1, "Reconstructed slice") return output_images
def find_cor(images: Images, slice_idx: int, start_cor: float, recon_params: ReconstructionParameters) -> float: """ Find the best CoR for this slice by maximising the squared sum of the reconstructed slice. Larger squared sum -> bigger deviance from the mean, i.e. larger distance between noise and data """ proj_angles = images.projection_angles() def get_sumsq(image: np.ndarray) -> float: return np.sum(image**2) def minimizer_function(cor): return -get_sumsq( AstraRecon.single_sino(images.sino(slice_idx), ScalarCoR(cor), proj_angles, recon_params)) return minimize(minimizer_function, start_cor, method='nelder-mead', tol=0.1).x[0]
def __init__(self, images: Images, slice_idx: int, initial_cor: ScalarCoR, recon_params: ReconstructionParameters, iters_mode: bool): self.image_width = images.width self.sino = images.sino(slice_idx) # Initial parameters if iters_mode: self.centre_value: Union[int, float] = INIT_ITERS_CENTRE_VALUE self.step = INIT_ITERS_STEP self.initial_cor = initial_cor self._recon_preview = self._recon_iters_preview self._divide_step = self._divide_iters_step else: self.centre_value = initial_cor.value self.step = self.image_width * 0.05 self._recon_preview = self._recon_cor_preview self._divide_step = self._divide_cor_step # Cache projection angles self.proj_angles = images.projection_angles(recon_params.max_projection_angle) self.recon_params = recon_params self.reconstructor = get_reconstructor_for(recon_params.algorithm)
def full(images: Images, cors: List[ScalarCoR], recon_params: ReconstructionParameters, progress: Optional[Progress] = None): """ Performs a volume reconstruction using sample data provided as sinograms. :param images: Array of sinogram images :param cors: Array of centre of rotation values :param proj_angles: Array of projection angles :param recon_params: Reconstruction Parameters :param progress: Optional progress reporter :return: 3D image data for reconstructed volume """ progress = Progress.ensure_instance(progress, task_name='TomoPy reconstruction') import multiprocessing ncores = multiprocessing.cpu_count() kwargs = { 'ncore': ncores, 'tomo': BaseRecon.prepare_sinogram(images.data, recon_params), 'sinogram_order': images._is_sinograms, 'theta': images.projection_angles(recon_params.max_projection_angle).value, 'center': [cor.value for cor in cors], 'algorithm': recon_params.algorithm, 'filter_name': recon_params.filter_name } with progress: volume = tomopy.recon(**kwargs) LOG.info('Reconstructed 3D volume with shape: {0}'.format( volume.shape)) return Images(volume)
def full(images: Images, cors: List[ScalarCoR], recon_params: ReconstructionParameters, progress: Optional[Progress] = None): """ Performs a volume reconstruction using sample data provided as sinograms. :param images: Array of sinogram images :param cors: Array of centre of rotation values :param proj_angles: Array of projection angles in radians :param recon_params: Reconstruction Parameters :param progress: Optional progress reporter :return: 3D image data for reconstructed volume """ progress = Progress.ensure_instance(progress, task_name='CIL reconstruction', num_steps=recon_params.num_iter + 1) projection_size = full_size_KB(images.data.shape, images.dtype) recon_volume_shape = images.data.shape[2], images.data.shape[ 2], images.data.shape[1] recon_volume_size = full_size_KB(recon_volume_shape, images.dtype) estimated_mem_required = 5 * projection_size + 13 * recon_volume_size free_mem = system_free_memory().kb() if (estimated_mem_required > free_mem): estimate_gb = estimated_mem_required / 1024 / 1024 raise RuntimeError( "The machine does not have enough physical memory available to allocate space for this data." f" Estimated RAM needed is {estimate_gb:.2f} GB") if cil_mutex.locked(): LOG.warning("CIL recon already in progress") with cil_mutex: progress.update(steps=1, msg='CIL: Setting up reconstruction', force_continue=False) angles = images.projection_angles( recon_params.max_projection_angle).value shape = images.data.shape pixel_num_h, pixel_num_v = shape[2], shape[1] pixel_size = 1. if recon_params.tilt is None: raise ValueError("recon_params.tilt is not set") rot_pos = [ (cors[pixel_num_v // 2].value - pixel_num_h / 2) * pixel_size, 0, 0 ] slope = -np.tan(np.deg2rad(recon_params.tilt.value)) rot_angle = [slope, 0, 1] ag = AcquisitionGeometry.create_Parallel3D( rotation_axis_position=rot_pos, rotation_axis_direction=rot_angle) ag.set_panel([pixel_num_h, pixel_num_v], pixel_size=(pixel_size, pixel_size)) ag.set_angles(angles=angles, angle_unit='radian') ag.set_labels(DataOrder.TIGRE_AG_LABELS) # stick it into an AcquisitionData data = ag.allocate(None) data.fill(BaseRecon.prepare_sinogram(images.data, recon_params)) data.reorder('astra') alpha = recon_params.alpha ig = ag.get_ImageGeometry() # set up TV regularisation K, f1, f2, G = CILRecon.set_up_TV_regularisation(ig, data, alpha) # alpha = 1.0 # f1 = alpha * MixedL21Norm() # f2 = 0.5 * L2NormSquared(b=ad2d) F = BlockFunction(f1, f2) normK = K.norm() sigma = 1 tau = 1 / (sigma * normK**2) pdhg = PDHG(f=F, g=G, operator=K, tau=tau, sigma=sigma, max_iteration=100000, update_objective_interval=10) with progress: for iter in range(recon_params.num_iter): progress.update( steps=1, msg= f'CIL: Iteration {iter+1} of {recon_params.num_iter}:' f'Objective {pdhg.get_last_objective():.2f}', force_continue=False) pdhg.next() volume = pdhg.solution.as_array() LOG.info('Reconstructed 3D volume with shape: {0}'.format( volume.shape)) return Images(volume)