Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bin/tofu
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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':
Expand Down
35 changes: 34 additions & 1 deletion tofu/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -852,19 +852,52 @@
'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',
'Laminographic reconstruction', 'Filtered backprojection',
'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
Expand Down
114 changes: 114 additions & 0 deletions tofu/rgbareco.py
Original file line number Diff line number Diff line change
@@ -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)