diff --git a/bin/tofu b/bin/tofu index f9c8e8c..05ff1c0 100755 --- a/bin/tofu +++ b/bin/tofu @@ -36,6 +36,9 @@ def run_genreco(args): from tofu import genreco genreco.genreco(args) +def run_rgba_bp(args): + from tofu import rgbareco + rgbareco.run_rgba_bp(args) def run_flat_correct(args): from tofu import preprocess @@ -214,6 +217,8 @@ def main(): ('interactive', run_shell, tomo_params, "Run interactive mode"), ('find-large-spots', run_find_large_spots, ('find-large-spots',), "Find large spots on images"), ('inpaint', run_inpaint, ('inpaint',), "Inpaint images"), + ('rgbabp', run_rgba_bp, config.RGBA_BP_PARAMS, "RGBA Backprojection for " + "parallel beam tomography") ] if sys.version < '3.7': diff --git a/tofu/config.py b/tofu/config.py index 27ce12d..fbd8a58 100644 --- a/tofu/config.py +++ b/tofu/config.py @@ -852,11 +852,44 @@ 'metavar': 'PATH'}, } +SECTIONS['rgba-backproject'] = { + 'burst': { + 'default': None, + 'type': restrict_value((0, None), dtype=int), + 'help': "Number of projections processed per kernel invocation"}, + 'overall-angle': { + 'default': None, + 'ezdefault': 360, + 'type': float, + 'unit': "deg", + 'help': "The total angle over which projections were taken"}, + 'center-position-x': { + 'default': None, + 'type': tupleize(), + 'unit': "pixel", + 'help': "X rotation axis position on a projection"}, + 'center-position-z': { + 'default': None, + 'ezdefault': "0", + 'type': tupleize(), + 'unit': "pixel", + 'help': "Z rotation axis position on a projection"}, + 'region': { + 'default': "0,1,1", + 'type': tupleize(num_items=3), + 'help': "z axis parameter region as from,to,step"}, + 'rgbabp-padding-mode': { + 'choices': ['none', 'clamp', 'clamp_to_edge', 'repeat', 'mirrored_repeat'], + 'default': 'clamp', + 'help': "Padded values assignment for the filtered projection"} +} + TOMO_PARAMS = ('flat-correction', 'reconstruction', 'tomographic-reconstruction', 'fbp', 'dfi', 'ir', 'sart', 'sbtv') PREPROC_PARAMS = ('preprocess', 'cone-beam-weight', 'flat-correction', 'retrieve-phase') LAMINO_PARAMS = PREPROC_PARAMS + ('laminographic-reconstruction',) GEN_RECO_PARAMS = PREPROC_PARAMS + ('general-reconstruction',) +RGBA_BP_PARAMS = ('preprocess', 'flat-correction', 'retrieve-phase', 'rgba-backproject') NICE_NAMES = ('General', 'Input', 'Flat field correction', 'Phase retrieval', 'Sinogram generation', 'General reconstruction', 'Tomographic reconstruction', @@ -864,7 +897,7 @@ 'Direct Fourier Inversion', 'Iterative reconstruction', 'SART', 'SBTV', 'GUI settings', 'Estimation', 'Performance', 'Preprocess', 'Cone beam weight', 'General reconstruction', 'Find large spots', - 'Inpaint') + 'Inpaint', 'Minimal IO', 'RGBA Backproject') # Add unit info to help strings diff --git a/tofu/rgbareco.py b/tofu/rgbareco.py new file mode 100644 index 0000000..9c1a6d2 --- /dev/null +++ b/tofu/rgbareco.py @@ -0,0 +1,114 @@ +import argparse +import logging +import time +from threading import Thread +from gi.repository import Ufo +from .preprocess import create_flat_correct_pipeline, create_projection_filtering_pipeline +from .tasks import get_task, get_writer +from .util import determine_shape, fbp_filtering_in_phase_retrieval + +LOG = logging.getLogger(__name__) + +def create_ffc_flt_pipeline( + args: argparse.Namespace, + graph: Ufo.TaskGraph, + processing_node: int) -> Ufo.TaskNode: + """ + Configures computational graph for flat-field correction and filtering. + + :param args: parameters for nodes. + :type args: argparse.Namespace + :param graph: Ufo task graph + :type graph: Ufo.TaskGraph + :param gpu_index: index of the gpu node + :type processing_node: int + :return: final task node after connecting flat-field to filtering + :rtype: Ufo.TaskNode + """ + current: Ufo.TaskNode = create_flat_correct_pipeline(args, graph, processing_node=processing_node) + if args.projection_filter != 'none' and not fbp_filtering_in_phase_retrieval(args): + pf_first, pf_last = create_projection_filtering_pipeline( + args, graph, processing_node=processing_node) + if current: + graph.connect_nodes(current, pf_first) + current = pf_last + return current + + +def setup_single_gpu_graph( + args: argparse.Namespace, + graph: Ufo.TaskGraph, + gpu_index: int=0) -> None: + """ + Configures full computational graph for reconstruction. + + :param args: parameters for nodes. + :type args: argparse.Namespace + :param graph: Ufo task graph. + :type graph: Ufo.TaskGraph + :param gpu_index: index of the gpu node + :type gpu_index: int + """ + determine_shape(args=args, store=True) + sink: Ufo.TaskNode = get_writer(params=args) + source: Ufo.TaskNode = create_ffc_flt_pipeline(args=args, graph=graph, processing_node=gpu_index) + backproject: Ufo.TaskNode = get_task('rgba-backproject', processing_node=gpu_index) + backproject.props.burst = args.burst + backproject.props.region = args.region + # Following is required when we want to perform the cropping after back-projection. For our + # testing we are enabling the parameter --projection-crop-after filter whereas default is + # backproject. Hence, we can keep the adjustment of center_position_x disabled as use the value + # provided in the command as is. + # args.center_position_x = [pos + padding / 2 for pos in args.center_position_x] + backproject.props.center_position_x = args.center_position_x + backproject.props.center_position_z = args.center_position_z + backproject.props.num_projections = args.number + backproject.props.overall_angle = args.overall_angle + backproject.props.addressing_mode = args.rgbabp_padding_mode + graph.connect_nodes(source, backproject) + graph.connect_nodes(backproject, sink) + +def run_rgba_bp(args: argparse.Namespace) -> None: + """ + Implements optimized backprojection leveraging RGBA color channels in texture memory. + + Required parameters in args: + For testing it is easier to focus on absorption reconstruction. Hence, we focus on the minimum + required parameters for flat-field correction with absorptivity, filtering and back-projection. + + - projections: location of the projections. + - flats: location of the flat fields. + - darks: location of the dark fields. + - output: location to write the final output slices. + - burst: number of projections to be processed per kernel invocation. + - number: number of projections to be processed. + - overall-angle: angles of rotation. + - center_position_x: axis of rotation + - center_position_z: z-position of the 0th slice. + - region: z-region for reconstruction (from, to, step) + - absorptivity: indicates to compute absorption (Beer-Lambert) from transmission. + - projection-crop-after: indicates to crop the projection (we use filter for efficiency, + default backproject) + + Example Command: + tofu rgbabp --projections radios --flats flats --darks darks/ --output slices.tiff --burst 24 \ + --number 3001 --overall-angle -180 --center-position-x 588.2 --center-position-z 606 \ + --region=-400,400,10 --absorptivity --projection-crop-after filter --verbose + """ + try: + assert args.darks + assert args.flats + assert args.projections + assert args.output + except AssertionError: + raise RuntimeError('test version: darks, flats, projections, output are needed') + print(f"###################################################Called#####") + st = time.time() + scheduler = Ufo.FixedScheduler() + graph = Ufo.TaskGraph() + _ = setup_single_gpu_graph(args=args, graph=graph) + thread = Thread(target=scheduler.run, args=(graph,), daemon=True) + thread.start() + thread.join() + duration = time.time() - st + LOG.debug('Duration: %.2f s', duration)