import tifffile from cil.framework import DataProcessor, ImageData, DataOrder import gi gi.require_version('Ufo', '0.0') from gi.repository import Ufo import numpy as np class UfoStackedBackProjector(DataProcessor): def __init__(self, volume_geometry=None, sinogram_geometry=None, precision_mode=None, stack_num=None): kwargs = { 'volume_geometry': volume_geometry, 'sinogram_geometry': sinogram_geometry, 'precision_mode': precision_mode, 'stack_num': stack_num} super(UfoStackedBackProjector, self).__init__(**kwargs) self.precision_mode = precision_mode self.stack_num = stack_num self.set_ImageGeometry(volume_geometry) self.set_AcquisitionGeometry(sinogram_geometry) def check_input(self, dataset): if self.sinogram_geometry.shape != dataset.geometry.shape: raise ValueError("Dataset not compatible with geometry used to create the projector") return True def set_ImageGeometry(self, volume_geometry): DataOrder.check_order_for_engine('astra', volume_geometry) if len(volume_geometry.dimension_labels) > 3: raise ValueError("Supports 2D and 3D data only, got {0}".format(volume_geometry.number_of_dimensions)) self.volume_geometry = volume_geometry.copy() def set_AcquisitionGeometry(self, sinogram_geometry): DataOrder.check_order_for_engine('astra', sinogram_geometry) if len(sinogram_geometry.dimension_labels) > 3: raise ValueError("Supports 2D and 3D data only, got {0}".format(self.volume_geometry.number_of_dimensions)) self.sinogram_geometry = sinogram_geometry.copy() def process(self, out=None): DATA = self.get_input() data_temp = DATA.as_array() arr_out = self.create_backprojection(data_temp, out) if out is None: out = ImageData(arr_out, deep_copy=False, geometry=self.volume_geometry.copy(), suppress_warning=True) return out else: out.fill(arr_out) def create_backprojection(self, sino, vol): pm = Ufo.PluginManager() graph = Ufo.TaskGraph() scheduler = Ufo.Scheduler() read = pm.get_task('memory-in') read.props.pointer = sino.__array_interface__['data'][0] read.props.width = sino.shape[0] read.props.height = sino.shape[1] read.props.number = sino.shape[2] read.props.bitdepth = 32 stack = pm.get_task('stack') stack.props.number = self.stack_num stacked_bp = pm.get_task('stacked-backproject') stacked_bp.props.axis_pos = sino.shape[1] / 2 stacked_bp.props.precision_mode = self.precision_mode vol_arr = np.zeros(self.volume_geometry.shape, dtype=np.float32) write = pm.get_task('memory-out') write.props.pointer = vol_arr.__array_interface__['data'][0] write.props.max_size = vol_arr.nbytes graph.connect_nodes(read, stack) graph.connect_nodes(stack, stacked_bp) graph.connect_nodes(stacked_bp, write) scheduler.run(graph) return vol_arr