def estimate_center_by_correlation(params): """Use correlation to estimate center of rotation for tomography.""" def flat_correct(flat, radio): nonzero = np.where(radio != 0) result = np.zeros_like(radio) result[nonzero] = flat[nonzero] / radio[nonzero] # log(1) = 0 result[result <= 0] = 1 return np.log(result) first = read_image(get_filenames(params.projections)[0]).astype(np.float) last_index = params.start + params.number if params.number else -1 last = read_image(get_filenames(params.projections)[last_index]).astype(np.float) if params.darks and params.flats: dark = read_image(get_filenames(params.darks)[0]).astype(np.float) flat = read_image(get_filenames(params.flats)[0]) - dark first = flat_correct(flat, first - dark) last = flat_correct(flat, last - dark) height = params.height if params.height else -1 y_region = slice(params.y, min(params.y + height, first.shape[0]), params.y_step) first = first[y_region, :] last = last[y_region, :] return compute_rotation_axis(first, last)
def find_axis_corr(self, ctset, vcrop, y, height, multipage): indir = self.make_inpaths(ctset[0], ctset[1]) """Use correlation to estimate center of rotation for tomography.""" from scipy.signal import fftconvolve def flat_correct(flat, radio): nonzero = np.where(radio != 0) result = np.zeros_like(radio) result[nonzero] = flat[nonzero] / radio[nonzero] # log(1) = 0 result[result <= 0] = 1 return np.log(result) if multipage: with tifffile.TiffFile(get_filenames(indir[2])[0]) as tif: first = tif.pages[0].asarray().astype(np.float) with tifffile.TiffFile(get_filenames(indir[2])[-1]) as tif: last = tif.pages[-1].asarray().astype(np.float) with tifffile.TiffFile(get_filenames(indir[0])[-1]) as tif: dark = tif.pages[-1].asarray().astype(np.float) with tifffile.TiffFile(get_filenames(indir[1])[0]) as tif: flat1 = tif.pages[-1].asarray().astype(np.float) - dark else: first = read_image(get_filenames(indir[2])[0]).astype(np.float) last = read_image(get_filenames(indir[2])[-1]).astype(np.float) dark = read_image(get_filenames(indir[0])[-1]).astype(np.float) flat1 = read_image(get_filenames(indir[1])[-1]) - dark first = flat_correct(flat1, first - dark) if ctset[1] == 4: if multipage: with tifffile.TiffFile(get_filenames(indir[3])[0]) as tif: flat2 = tif.pages[-1].asarray().astype(np.float) - dark else: flat2 = read_image(get_filenames(indir[3])[-1]) - dark last = flat_correct(flat2, last - dark) else: last = flat_correct(flat1, last - dark) if vcrop: y_region = slice(y, min(y + height, first.shape[0]), 1) first = first[y_region, :] last = last[y_region, :] width = first.shape[1] first = first - first.mean() last = last - last.mean() conv = fftconvolve(first, last[::-1, :], mode='same') center = np.unravel_index(conv.argmax(), conv.shape)[1] return (width / 2.0 + center) / 2.0
def bad_vert_ROI(multipage, path2proj, y, height): if multipage: with tifffile.TiffFile(get_filenames(path2proj)[0]) as tif: proj = tif.pages[0].asarray().astype(np.float) else: proj = read_image(get_filenames(path2proj)[0]).astype(np.float) y_region = slice(y, min(y + height, proj.shape[0]), 1) proj = proj[y_region, :] if proj.shape[0] == 0: return True else: return False
def find_axis_std(self, ctset, tmpdir, ax_range, p_width, search_row, nviews): indir = self.make_inpaths(ctset[0], ctset[1]) print indir[2] image = read_image(get_filenames(indir[2])[0]) cmd = 'tofu lamino --absorptivity --fix-nan-and-inf --overall-angle 180'\ ' --lamino-angle 90 --height 2' cmd += ' --darks {} --flats {} --projections {}'.\ format(indir[0], indir[1], enquote(indir[2])) cmd += ' --number {}'.format(nviews) cmd += ' --angle {:0.5f}'.format(np.radians(180.0 / float(nviews))) if ctset[1] == 4: cmd += ' --flats2 {}'.format(indir[3]) out_pattern = os.path.join(tmpdir, "axis-search/slice") cmd += ' --output {}'.format(enquote(out_pattern)) cmd += ' --x-region={},{},{}'.format(-p_width / 2, p_width / 2, 1) cmd += ' --y-region={},{},{}'.format(-p_width / 2, p_width / 2, 1) cmd += ' --y {} --height 2'.format(search_row) cmd += ' --z-parameter x-center' cmd += ' --region={}'.format(enquote(ax_range)) cmd += ' --z 0' res = [float(num) for num in ax_range.split(',')] cmd += ' --axis {},{}'.format((res[0] + res[1]) / 2., 1.0) #middle of ax search range? cmd += " --output-bytes-per-file 0" # cmd += ' --delete-slice-dir' print cmd os.system(cmd) points, maximum = evaluate_images_simp(out_pattern + '*.tif', "msag") return res[0] + res[2] * maximum
def lamino(params): """Laminographic reconstruction utilizing all GPUs.""" LOG.info('Z parameter: {}'.format(params.z_parameter)) if not params.overall_angle: params.overall_angle = 360. LOG.info('Overall angle not specified, using 360 deg') if not params.angle: if params.dry_run: if not params.number: raise ValueError('--number must be specified by --dry-run') num_files = params.number else: num_files = len(get_filenames(params.projections)) if not num_files: raise RuntimeError("No files found in `{}'".format( params.projections)) params.angle = params.overall_angle / num_files * params.step LOG.info('Angle not specified, calculating from ' + '{} projections and step {}: {} deg'.format( num_files, params.step, params.angle)) if not (params.width and params.height): proj_width, proj_height = determine_shape(params, params.projections) if not proj_width: raise RuntimeError("Could not determine width from the input") if not params.number: params.number = int( np.round(np.abs(params.overall_angle / params.angle))) if not params.width: params.width = proj_width if not params.height: params.height = proj_height - params.y if params.dry_run: LOG.info('Dummy data W x H x N: {} x {} x {}'.format( params.width, params.height, params.number)) params.projection_filter_scale = np.sin(np.deg2rad(params.lamino_angle)) # For now we need to make a workaround for the memory leak, which means we need to execute # the passes in separate processes to clean up the low level code. For that we also need to # call the region-splitting in a separate function. # TODO: Simplify after the memory leak fix! queue = Queue() proc = Process(target=_create_runs, args=( params, queue, )) proc.start() proc.join() x_region, y_region, regions, num_gpus = queue.get() for i in range(0, len(regions), num_gpus): z_subregion = regions[i:min(i + num_gpus, len(regions))] LOG.info('Computing slices {}..{}'.format(z_subregion[0][0], z_subregion[-1][1])) proc = Process(target=_run, args=(params, x_region, y_region, z_subregion, i / num_gpus)) proc.start() proc.join()
def make_copy_of_flat(flatdir, flat_copy_name, dryrun): first_flat_file = get_first_filename(flatdir) try: shape = get_image_shape(first_flat_file) except: raise ValueError('Failed to determine size and number of flats in {}'.format(flatdir)) cmd = "" if len(shape) == 2: last_flat_file = get_filenames(flatdir)[-1] cmd = "cp {} {}".format(last_flat_file, flat_copy_name) else: flat = read_image(get_filenames(flatdir)[-1])[-1] if dryrun: cmd = "echo Will save a copy of flat into \"{}\"".format(flat_copy_name) else: tifffile.imsave(flat_copy_name, flat) return cmd
def get_dims(pth): # get number of projections and projections dimensions first_proj = get_first_filename(pth) multipage = False try: shape = get_image_shape(first_proj) except: raise ValueError('Failed to determine size and number of projections in {}'.format(pth)) if len(shape) == 2: # single page input return len(get_filenames(pth)), [shape[-2], shape[-1]], multipage elif len(shape) == 3: # multipage input nviews = 0 for i in get_filenames(pth): nviews += get_image_shape(i)[0] multipage = True return nviews, [shape[-2], shape[-1]], multipage return -6, [-6, -6]
def get_dims(pth, args): #must be changed if multipage tiff input!!! # get number of projections and projections dimensions if not args.bigtif_inp: tomos = get_filenames(pth) image = read_image(tomos[0]) return len(tomos), image.shape else: return args.nviews, [args.H, args.W]
def main(): args = parse_args() sinos = get_filenames(os.path.join(args.sinos, '*.tif')) #create output directory wdir = os.path.split(args.sinos)[0] odir = os.path.join(wdir, 'sinos-filt') if not os.path.exists(odir): os.makedirs(odir) pool = mp.Pool(processes=mp.cpu_count()) exec_func = partial(RR, args.mws, odir) pool.map(exec_func, sinos)
def lamino(params): """Laminographic reconstruction utilizing all GPUs.""" LOG.info('Z parameter: {}'.format(params.z_parameter)) if not params.overall_angle: params.overall_angle = 360. LOG.info('Overall angle not specified, using 360 deg') if not params.angle: if params.dry_run: if not params.number: raise ValueError('--number must be specified by --dry-run') num_files = params.number else: num_files = len(get_filenames(params.projections)) if not num_files: raise RuntimeError("No files found in `{}'".format(params.projections)) params.angle = params.overall_angle / num_files * params.step LOG.info('Angle not specified, calculating from ' + '{} projections and step {}: {} deg'.format(num_files, params.step, params.angle)) if not (params.width and params.height): proj_width, proj_height = determine_shape(params, params.projections) if not proj_width: raise RuntimeError("Could not determine width from the input") if not params.number: params.number = int(np.round(np.abs(params.overall_angle / params.angle))) if not params.width: params.width = proj_width if not params.height: params.height = proj_height - params.y if params.dry_run: LOG.info('Dummy data W x H x N: {} x {} x {}'.format(params.width, params.height, params.number)) # For now we need to make a workaround for the memory leak, which means we need to execute # the passes in separate processes to clean up the low level code. For that we also need to # call the region-splitting in a separate function. # TODO: Simplify after the memory leak fix! queue = Queue() proc = Process(target=_create_runs, args=(params, queue,)) proc.start() proc.join() x_region, y_region, regions, num_gpus = queue.get() for i in range(0, len(regions), num_gpus): z_subregion = regions[i:min(i + num_gpus, len(regions))] LOG.info('Computing slices {}..{}'.format(z_subregion[0][0], z_subregion[-1][1])) proc = Process(target=_run, args=(params, x_region, y_region, z_subregion, i / num_gpus)) proc.start() proc.join()
def create_sinogram_pipeline(args, graph): """Create sinogram generating pipeline based on arguments from *args*.""" pm = Ufo.PluginManager() sinos = pm.get_task('transpose-projections') if args.number: region = (args.start, args.start + args.number, args.step) num_projections = len(range(*region)) else: num_projections = len(get_filenames(args.projections)) sinos.props.number = num_projections if args.darks and args.flats: start = create_flat_correct_pipeline(args, graph) else: start = pm.get_task('read') start.props.path = args.projections set_node_props(start, args) graph.connect_nodes(start, sinos) return sinos
def prepare_angular_arguments(params): if not params.overall_angle: params.overall_angle = 360. LOG.info('Overall angle not specified, using 360 deg') if not params.angle: if params.dry_run: if not params.number: raise ValueError('--number must be specified by --dry-run') num_files = params.number else: num_files = len(get_filenames(params.projections)) if not num_files: raise RuntimeError("No files found in `{}'".format(params.projections)) params.angle = params.overall_angle / num_files * params.step LOG.info('Angle not specified, calculating from ' + '{} projections and step {}: {} deg'.format(num_files, params.step, params.angle)) determine_shape(params, params.projections, store=True) if not params.number: params.number = int(np.round(np.abs(params.overall_angle / params.angle))) if params.dry_run: LOG.info('Dummy data W x H x N: {} x {} x {}'.format(params.width, params.height, params.number))
def create_flat_correct_pipeline(args, graph): """ Create flat field correction pipeline. All the settings are provided in *args*. *graph* is used for making the connections. Returns the flat field correction task which can be used for further pipelining. """ pm = Ufo.PluginManager() if args.projections is None or args.flats is None or args.darks is None: raise RuntimeError("You must specify --projections, --flats and --darks.") def get_task(name, **kwargs): """Get task *name* with properties *kwargs*.""" task = pm.get_task(name) task.set_properties(**kwargs) return task reader = get_task('read') dark_reader = get_task('read') flat_before_reader = get_task('read') ffc = get_task('flat-field-correct', dark_scale=args.dark_scale, absorption_correct=args.absorptivity, fix_nan_and_inf=args.fix_nan_and_inf) mode = args.reduction_mode.lower() roi_args = make_subargs(args, ['y', 'height', 'y_step']) set_node_props(reader, args) set_node_props(dark_reader, roi_args) set_node_props(flat_before_reader, roi_args) for r, path in ((reader, args.projections), (dark_reader, args.darks), (flat_before_reader, args.flats)): setup_read_task(r, path, args) LOG.debug("Doing flat field correction using reduction mode `{}'".format(mode)) if args.flats2: flat_after_reader = get_task('read') setup_read_task(flat_after_reader, args.flats2, args) set_node_props(flat_after_reader, roi_args) num_files = len(get_filenames(args.projections)) can_read = len(range(args.start, num_files, args.step)) number = args.number if args.number else num_files num_read = min(can_read, number) flat_interpolate = get_task('interpolate', number=num_read) if args.resize: LOG.debug("Resize input data by factor of {}".format(args.resize)) proj_bin = get_task('bin', size=args.resize) dark_bin = get_task('bin', size=args.resize) flat_bin = get_task('bin', size=args.resize) graph.connect_nodes(reader, proj_bin) graph.connect_nodes(dark_reader, dark_bin) graph.connect_nodes(flat_before_reader, flat_bin) reader, dark_reader, flat_before_reader = proj_bin, dark_bin, flat_bin if args.flats2: flat_bin = get_task('bin', size=args.resize) graph.connect_nodes(flat_after_reader, flat_bin) flat_after_reader = flat_bin if mode == 'median': dark_stack = get_task('stack', number=len(get_filenames(args.darks))) dark_reduced = get_task('flatten', mode='median') flat_before_stack = get_task('stack', number=len(get_filenames(args.flats))) flat_before_reduced = get_task('flatten', mode='median') graph.connect_nodes(dark_reader, dark_stack) graph.connect_nodes(dark_stack, dark_reduced) graph.connect_nodes(flat_before_reader, flat_before_stack) graph.connect_nodes(flat_before_stack, flat_before_reduced) if args.flats2: flat_after_stack = get_task('stack', number=len(get_filenames(args.flats2))) flat_after_reduced = get_task('flatten', mode='median') graph.connect_nodes(flat_after_reader, flat_after_stack) graph.connect_nodes(flat_after_stack, flat_after_reduced) elif mode == 'average': dark_reduced = get_task('average') flat_before_reduced = get_task('average') graph.connect_nodes(dark_reader, dark_reduced) graph.connect_nodes(flat_before_reader, flat_before_reduced) if args.flats2: flat_after_reduced = get_task('average') graph.connect_nodes(flat_after_reader, flat_after_reduced) else: raise ValueError('Invalid reduction mode') graph.connect_nodes_full(reader, ffc, 0) graph.connect_nodes_full(dark_reduced, ffc, 1) if args.flats2: graph.connect_nodes_full(flat_before_reduced, flat_interpolate, 0) graph.connect_nodes_full(flat_after_reduced, flat_interpolate, 1) graph.connect_nodes_full(flat_interpolate, ffc, 2) else: graph.connect_nodes_full(flat_before_reduced, ffc, 2) return ffc
def tomo(params): # Create reader and writer if params.projections and params.sinograms: raise RuntimeError("Cannot specify both --projections and --sinograms.") if params.projections is None and params.sinograms is None: reader, width, height = get_dummy_reader(params) else: if params.projections: reader, width, height = get_projection_reader(params) else: reader, width, height = get_sinogram_reader(params) axis = params.axis or width / 2.0 if params.projections and params.resize: width /= params.resize height /= params.resize axis /= params.resize LOG.debug("Input dimensions: {}x{} pixels".format(width, height)) writer = get_writer(pm, params) # Setup graph depending on the chosen method and input data g = Ufo.TaskGraph() if params.projections is not None: if params.number: count = len(range(params.start, params.start + params.number, params.step)) else: count = len(get_filenames(params.projections)) LOG.debug("Number of projections: {}".format(count)) sino_output = get_task('transpose-projections', number=count) if params.darks and params.flats: g.connect_nodes(create_flat_correct_pipeline(params, g), sino_output) else: g.connect_nodes(reader, sino_output) if height: # Sinogram height is the one needed for further padding height = count else: sino_output = reader if params.method == 'fbp': fft = get_task('fft', dimensions=1) ifft = get_task('ifft', dimensions=1) fltr = get_task('filter', filter=params.projection_filter) bp = get_task('backproject', axis_pos=axis) if params.angle: bp.props.angle_step = params.angle if params.offset: bp.props.angle_offset = params.offset if width and height: # Pad the image with its extent to prevent reconstuction ring pad = get_task('pad') crop = get_task('crop') setup_padding(pad, crop, width, height, params.projection_padding_mode) LOG.debug("Padding input to: {}x{} pixels".format(pad.props.width, pad.props.height)) g.connect_nodes(sino_output, pad) g.connect_nodes(pad, fft) g.connect_nodes(fft, fltr) g.connect_nodes(fltr, ifft) g.connect_nodes(ifft, crop) g.connect_nodes(crop, bp) else: if params.crop_width: ifft.props.crop_width = int(params.crop_width) LOG.debug("Cropping to {} pixels".format(ifft.props.crop_width)) g.connect_nodes(sino_output, fft) g.connect_nodes(fft, fltr) g.connect_nodes(fltr, ifft) g.connect_nodes(ifft, bp) g.connect_nodes(bp, writer) if params.method in ('sart', 'sirt', 'sbtv', 'asdpocs'): projector = pm.get_task_from_package('ir', 'parallel-projector') projector.set_properties(model='joseph', is_forward=False) projector.set_properties(axis_position=axis) projector.set_properties(step=params.angle if params.angle else np.pi / 180.0) method = pm.get_task_from_package('ir', params.method) method.set_properties(projector=projector, num_iterations=params.num_iterations) if params.method in ('sart', 'sirt'): method.set_properties(relaxation_factor=params.relaxation_factor) if params.method == 'asdpocs': minimizer = pm.get_task_from_package('ir', 'sirt') method.set_properties(df_minimizer=minimizer) if params.method == 'sbtv': # FIXME: the lambda keyword is preventing from the following # assignment ... # method.props.lambda = params.lambda method.set_properties(mu=params.mu) g.connect_nodes(sino_output, method) g.connect_nodes(method, writer) if params.method == 'dfi': oversampling = params.oversampling or 1 pad = get_task('zeropad', center_of_rotation=axis, oversampling=oversampling) fft = get_task('fft', dimensions=1, auto_zeropadding=0) dfi = get_task('dfi-sinc') ifft = get_task('ifft', dimensions=2) swap_forward = get_task('swap-quadrants') swap_backward = get_task('swap-quadrants') if params.angle: dfi.props.angle_step = params.angle g.connect_nodes(sino_output, pad) g.connect_nodes(pad, fft) g.connect_nodes(fft, dfi) g.connect_nodes(dfi, swap_forward) g.connect_nodes(swap_forward, ifft) g.connect_nodes(ifft, swap_backward) if width: crop = get_task('crop') crop.set_properties(from_center=True, width=width, height=width) g.connect_nodes(swap_backward, crop) g.connect_nodes(crop, writer) else: g.connect_nodes(swap_backward, writer) scheduler = Ufo.Scheduler() if hasattr(scheduler.props, 'enable_tracing'): LOG.debug("Use tracing: {}".format(params.enable_tracing)) scheduler.props.enable_tracing = params.enable_tracing scheduler.run(g) duration = scheduler.props.time LOG.info("Execution time: {} s".format(duration)) return duration
def create_flat_correct_pipeline(args, graph): """ Create flat field correction pipeline. All the settings are provided in *args*. *graph* is used for making the connections. Returns the flat field correction task which can be used for further pipelining. """ pm = Ufo.PluginManager() if args.projections is None or args.flats is None or args.darks is None: raise RuntimeError( "You must specify --projections, --flats and --darks.") def get_task(name, **kwargs): """Get task *name* with properties *kwargs*.""" task = pm.get_task(name) task.set_properties(**kwargs) return task reader = get_task('read') dark_reader = get_task('read') flat_before_reader = get_task('read') ffc = get_task('flat-field-correct', dark_scale=args.dark_scale, absorption_correct=args.absorptivity, fix_nan_and_inf=args.fix_nan_and_inf) mode = args.reduction_mode.lower() roi_args = make_subargs(args, ['y', 'height', 'y_step']) set_node_props(reader, args) set_node_props(dark_reader, roi_args) set_node_props(flat_before_reader, roi_args) for r, path in ((reader, args.projections), (dark_reader, args.darks), (flat_before_reader, args.flats)): setup_read_task(r, path, args) LOG.debug( "Doing flat field correction using reduction mode `{}'".format(mode)) if args.flats2: flat_after_reader = get_task('read') setup_read_task(flat_after_reader, args.flats2, args) set_node_props(flat_after_reader, roi_args) num_files = len(get_filenames(args.projections)) can_read = len(range(args.start, num_files, args.step)) number = args.number if args.number else num_files num_read = min(can_read, number) flat_interpolate = get_task('interpolate', number=num_read) if args.resize: LOG.debug("Resize input data by factor of {}".format(args.resize)) proj_bin = get_task('bin', size=args.resize) dark_bin = get_task('bin', size=args.resize) flat_bin = get_task('bin', size=args.resize) graph.connect_nodes(reader, proj_bin) graph.connect_nodes(dark_reader, dark_bin) graph.connect_nodes(flat_before_reader, flat_bin) reader, dark_reader, flat_before_reader = proj_bin, dark_bin, flat_bin if args.flats2: flat_bin = get_task('bin', size=args.resize) graph.connect_nodes(flat_after_reader, flat_bin) flat_after_reader = flat_bin if mode == 'median': dark_stack = get_task('stack', number=len(get_filenames(args.darks))) dark_reduced = get_task('flatten', mode='median') flat_before_stack = get_task('stack', number=len(get_filenames(args.flats))) flat_before_reduced = get_task('flatten', mode='median') graph.connect_nodes(dark_reader, dark_stack) graph.connect_nodes(dark_stack, dark_reduced) graph.connect_nodes(flat_before_reader, flat_before_stack) graph.connect_nodes(flat_before_stack, flat_before_reduced) if args.flats2: flat_after_stack = get_task('stack', number=len(get_filenames(args.flats2))) flat_after_reduced = get_task('flatten', mode='median') graph.connect_nodes(flat_after_reader, flat_after_stack) graph.connect_nodes(flat_after_stack, flat_after_reduced) elif mode == 'average': dark_reduced = get_task('average') flat_before_reduced = get_task('average') graph.connect_nodes(dark_reader, dark_reduced) graph.connect_nodes(flat_before_reader, flat_before_reduced) if args.flats2: flat_after_reduced = get_task('average') graph.connect_nodes(flat_after_reader, flat_after_reduced) else: raise ValueError('Invalid reduction mode') graph.connect_nodes_full(reader, ffc, 0) graph.connect_nodes_full(dark_reduced, ffc, 1) if args.flats2: graph.connect_nodes_full(flat_before_reduced, flat_interpolate, 0) graph.connect_nodes_full(flat_after_reduced, flat_interpolate, 1) graph.connect_nodes_full(flat_interpolate, ffc, 2) else: graph.connect_nodes_full(flat_before_reduced, ffc, 2) return ffc
def frmt_ufo_cmds(cmds, ctset, out_pattern, ax, args, Tofu, Ufo, FindCOR, nviews, WH): '''formats list of processing commands for a CT set''' ############ Preprocessing commands: working on projections #must be made compatible with multipage tiffs #any_flat = get_filenames(os.path.join(ctset[0],Tofu._fdt_names[1]))[1] any_flat = get_filenames(os.path.join(ctset[0], Tofu._fdt_names[1]))[0] # make a copy of original flat-field file in case if inp is enabled if args.inp and args.pre: any_flat_copy = os.path.join(args.tmpdir, 'flat.tif') cmds.append("cp {} {}".format(any_flat, any_flat_copy)) any_flat = any_flat_copy if args.pre: cmds.append("echo \" - Preprocessing \"") cmds_prepro = Ufo.get_pre_cmd(ctset, args.pre_cmd, args.tmpdir) cmds.extend(cmds_prepro) # reset location of input data ctset = (args.tmpdir, ctset[1]) ################################################### if args.inp: # generate commands to "inpaint" projections cmds.append("echo \" - Inpainting\"") cmds_inpaint = Ufo.get_inp_cmd(ctset, args.tmpdir, args, WH[0], nviews, any_flat) # reset location of input data ctset = (args.tmpdir, ctset[1]) cmds.extend(cmds_inpaint) ######### Projections ready ############# ######### If RR is not enabled we do not need sinograms ######## if (not args.RR): if args.inp and (not args.PR): cmds.append( "echo \" - CT with axis {}; no ffc, no PR\"".format(ax)) cmds.append( Tofu.get_reco_cmd(ctset, out_pattern, ax, args, nviews, WH, False, False)) elif args.inp and args.PR: cmds.append( "echo \" - Phase retrieval from inpainted projections\"") cmds.extend( Ufo.get_pr_ufo_cmd(ctset, args, args.tmpdir, nviews, WH)) cmds.append( "echo \" - CT with axis {}; no ffc, no PR\"".format(ax)) cmds.append( Tofu.get_reco_cmd(ctset, out_pattern, ax, args, nviews, WH, False, False)) elif (not args.inp) and args.PR: cmds.append("echo \" - CT with axis {}; ffc and PR\"".format(ax)) cmds.append( Tofu.get_reco_cmd(ctset, out_pattern, ax, args, nviews, WH, True, True)) elif (not args.inp) and (not args.PR): cmds.append("echo \" - CT with axis {}; ffc, no PR\"".format(ax)) cmds.append( Tofu.get_reco_cmd(ctset, out_pattern, ax, args, nviews, WH, True, False)) ################# RING REMOVAL ####################### if args.RR: # Generate sinograms if args.PR: # we need to do phase retrieval if args.inp: # if inp was requested flat field correction has been done already cmds.append( "echo \" - Phase retrieval from inpainted projections\"") cmds.extend( Ufo.get_pr_ufo_cmd(ctset, args, args.tmpdir, nviews, WH)) else: cmds.append("echo \" - Phase retrieval with flat-correction\"") cmds.append(Tofu.get_pr_tofu_cmd(ctset, args, nviews, WH[0])) cmds.append( "echo \" - Make sinograms from phase-retrieved projections\"") cmds.append(Tofu.get_sinos_noffc_cmd(args.tmpdir, args, nviews, WH)) else: # we do not need to do phase retrieval if args.inp: # if inp was requested flat field correction has been done already cmds.append( "echo \" - Make sinograms from inpainted projections\"") cmds.append( Tofu.get_sinos_noffc_cmd(args.tmpdir, args, nviews, WH)) else: cmds.append("echo \" - Make sinograms with flat-correction\"") cmds.append( Tofu.get_sinos_ffc_cmd(ctset, args.tmpdir, args, nviews, WH)) # Filter sinograms if (args.RR_par >= 1) and (args.RR_par <= 3): cmds.append("echo \" - Ring removal - ufo 1d stripes filter\"") cmds.append( Ufo.get_filter_sinos_cmd(ctset[0], args.tmpdir, args.RR_par, nviews, WH[1])) elif args.RR_par > 5: cmds.append("echo \" - Ring removal - median filter\"") #note - calling an external program, not ufo-kit script tmp = os.path.dirname(os.path.abspath(__file__)) path_to_filt = os.path.join(tmp, 'ez_RR_simple.py') if os.path.isfile(path_to_filt): tmp = os.path.join(args.tmpdir, "sinos") cmdtmp = '{} --sinos {} --mws {}'\ .format(path_to_filt, tmp, args.RR_par) cmds.append(cmdtmp) else: cmds.append( "echo \"Omitting RR because file with filter does not exist\"" ) if not args.keep_tmp: cmds.append('rm -rf {}'.format(os.path.join(args.tmpdir, 'sinos'))) # Preparation for final CT command cmds.append("echo \" - Generating proj from filtered sinograms\"") cmds.append(Tofu.get_sinos2proj_cmd(args, WH[0])) # reset location of input data ctset = (args.tmpdir, ctset[1]) #Finally tofu reco without ffc and PR cmds.append("echo \" - CT with axis {}\"".format(ax)) cmds.append( Tofu.get_reco_cmd(ctset, out_pattern, ax, args, nviews, WH, False, False)) return nviews, WH
def tomo(params): # Create reader and writer if params.projections and params.sinograms: raise RuntimeError("Cannot specify both --projections and --sinograms.") if params.projections is None and params.sinograms is None: reader, width, height = get_dummy_reader(params) else: if params.projections: reader, width, height = get_projection_reader(params) else: reader, width, height = get_sinogram_reader(params) axis = params.axis or width / 2.0 if params.projections and params.resize: width /= params.resize height /= params.resize axis /= params.resize LOG.debug("Input dimensions: {}x{} pixels".format(width, height)) writer = get_writer(params) # Setup graph depending on the chosen method and input data g = Ufo.TaskGraph() if params.projections is not None: if params.number: count = len(range(params.start, params.start + params.number, params.step)) else: count = len(get_filenames(params.projections)) LOG.debug("Number of projections: {}".format(count)) sino_output = get_task('transpose-projections', number=count) if params.darks and params.flats: g.connect_nodes(create_flat_correct_pipeline(params, g), sino_output) else: g.connect_nodes(reader, sino_output) if height: # Sinogram height is the one needed for further padding height = count else: sino_output = reader if params.method == 'fbp': fft = get_task('fft', dimensions=1) ifft = get_task('ifft', dimensions=1) fltr = get_task('filter', filter=params.projection_filter) bp = get_task('backproject', axis_pos=axis) if params.angle: bp.props.angle_step = params.angle if params.offset: bp.props.angle_offset = params.offset if width and height: # Pad the image with its extent to prevent reconstuction ring pad = get_task('pad') crop = get_task('crop') setup_padding(pad, crop, width, height) LOG.debug("Padding input to: {}x{} pixels".format(pad.props.width, pad.props.height)) g.connect_nodes(sino_output, pad) g.connect_nodes(pad, fft) g.connect_nodes(fft, fltr) g.connect_nodes(fltr, ifft) g.connect_nodes(ifft, crop) g.connect_nodes(crop, bp) else: if params.crop_width: ifft.props.crop_width = int(params.crop_width) LOG.debug("Cropping to {} pixels".format(ifft.props.crop_width)) g.connect_nodes(sino_output, fft) g.connect_nodes(fft, fltr) g.connect_nodes(fltr, ifft) g.connect_nodes(ifft, bp) g.connect_nodes(bp, writer) if params.method in ('sart', 'sirt', 'sbtv', 'asdpocs'): projector = pm.get_task_from_package('ir', 'parallel-projector') projector.set_properties(model='joseph', is_forward=False) projector.set_properties(axis_position=axis) projector.set_properties(step=params.angle if params.angle else np.pi / 180.0) method = pm.get_task_from_package('ir', params.method) method.set_properties(projector=projector, num_iterations=params.num_iterations) if params.method in ('sart', 'sirt'): method.set_properties(relaxation_factor=params.relaxation_factor) if params.method == 'asdpocs': minimizer = pm.get_task_from_package('ir', 'sirt') method.set_properties(df_minimizer=minimizer) if params.method == 'sbtv': # FIXME: the lambda keyword is preventing from the following # assignment ... # method.props.lambda = params.lambda method.set_properties(mu=params.mu) g.connect_nodes(sino_output, method) g.connect_nodes(method, writer) if params.method == 'dfi': oversampling = params.oversampling or 1 pad = get_task('zeropad', center_of_rotation=axis, oversampling=oversampling) fft = get_task('fft', dimensions=1, auto_zeropadding=0) dfi = get_task('dfi-sinc') ifft = get_task('ifft', dimensions=2) swap_forward = get_task('swap-quadrants') swap_backward = get_task('swap-quadrants') if params.angle: dfi.props.angle_step = params.angle g.connect_nodes(sino_output, pad) g.connect_nodes(pad, fft) g.connect_nodes(fft, dfi) g.connect_nodes(dfi, swap_forward) g.connect_nodes(swap_forward, ifft) g.connect_nodes(ifft, swap_backward) if width: crop = get_task('crop') crop.set_properties(from_center=True, width=width, height=width) g.connect_nodes(swap_backward, crop) g.connect_nodes(crop, writer) else: g.connect_nodes(swap_backward, writer) scheduler = Ufo.Scheduler() if hasattr(scheduler.props, 'enable_tracing'): LOG.debug("Use tracing: {}".format(params.enable_tracing)) scheduler.props.enable_tracing = params.enable_tracing scheduler.run(g) duration = scheduler.props.time LOG.info("Execution time: {} s".format(duration)) return duration