示例#1
0
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)
示例#2
0
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)
示例#3
0
    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
示例#4
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
示例#5
0
 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
示例#6
0
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()
示例#7
0
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
示例#8
0
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]
示例#9
0
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]
示例#10
0
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)
示例#11
0
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()
示例#12
0
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
示例#13
0
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
示例#14
0
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))
示例#15
0
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
示例#16
0
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
示例#17
0
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
示例#18
0
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
示例#19
0
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