コード例 #1
0
def main():

    # direct all engine's messages to files
    msg_red = MessageRedirector('info.txt', 'warn.txt', 'errr.txt')

    # select acquisition data storage scheme
    AcquisitionData.set_storage_scheme(storage)

    # obtain an acquisition data template
    template = AcquisitionData(temp_file)

    # create a uniform acquisition data from template
    acq_data = AcquisitionData(template)
    acq_data.fill(1.0)

    # create acquisition sensitivity model from ECAT8 normalization data
    asm = AcquisitionSensitivityModel(norm_file)
    asm.set_up(template)

    # apply normalization to the uniform acquisition data to obtain
    # bin efficiencies
    fwd_data = asm.forward(acq_data)

    # show bin efficiencies
    acq_array = fwd_data.as_array()
    acq_dim = acq_array.shape
    z = acq_dim[1]//2
    if show_plot:
        show_2D_array('Bin efficiencies', acq_array[0,z,:,:])
コード例 #2
0
def main():

    # direct all engine's messages to files
    msg_red = MessageRedirector('info.txt', 'warn.txt', 'errr.txt')

    # select acquisition data storage scheme
    AcquisitionData.set_storage_scheme(storage)

    # obtain an acquisition data template
    template = AcquisitionData(temp_file)

    # create uniform acquisition data from template
    print('creating uniform acquisition data...')
    acq_data = AcquisitionData(template)
    acq_data.fill(1.0)

    # read attenuation image
    attn_image = ImageData(attn_file)
    attn_image_as_array = attn_image.as_array()
    z = attn_image_as_array.shape[0]//2
    if show_plot:
        show_2D_array('Attenuation image', attn_image_as_array[z,:,:])

    # create acquisition model
    am = AcquisitionModelUsingRayTracingMatrix()
    am.set_up(template, attn_image)

    # create acquisition sensitivity model from attenuation image
    print('creating acquisition sensitivity model...')
    asm = AcquisitionSensitivityModel(attn_image, am)
    asm.set_up(template)
    am.set_acquisition_sensitivity(asm)
##    print('projecting (please wait, may take a while)...')
##    simulated_data = am.forward(attn_image)

    # apply attenuation to the uniform acquisition data to obtain
    # 'bin efficiencies'
    print('applying attenuation (please wait, may take a while)...')
    asm.unnormalise(acq_data)

    # If desired, save attenuation factors
    if args['--output']:
        acq_data.write(args['--output'])

    # show 'bin efficiencies'
    acq_array = acq_data.as_array()
    acq_dim = acq_array.shape
    z = acq_dim[1]//2
    if show_plot:
        show_2D_array('Bin efficiencies', acq_array[0,z,:,:])
コード例 #3
0
def main():

    # select acquisition data storage scheme
    AcquisitionData.set_storage_scheme(storage)

    # read acquisition data template
    acq_data_template = AcquisitionData(tmpl_file)

    # create listmode-to-sinograms converter object
    lm2sino = ListmodeToSinograms()

    # set input, output and template files
    lm2sino.set_input(list_file)
    lm2sino.set_output_prefix(sino_file)
    # the template is used to specify the sizes of the output sinogram.
    # see the acquisition_data_from_scanner_info demo for an example how to 
    # make your own template file
    lm2sino.set_template(acq_data_template)
    # old way (now just an alternative option)
    # lm2sino.set_template(tmpl_file)

    # set interval
    lm2sino.set_time_interval(interval[0], interval[1])

    # set some flags as examples (the following values are the defaults)
    lm2sino.flag_on('store_prompts')
    lm2sino.flag_off('interactive')

    # set up the converter
    lm2sino.set_up()

    # convert
    lm2sino.process()

    # get access to the sinograms
    acq_data = lm2sino.get_output()
    # copy the acquisition data into a Python array
    acq_array = acq_data.as_array()
    acq_dim = acq_array.shape
    print('acquisition data dimensions: %dx%dx%dx%d' % acq_dim)
    z = acq_dim[1]//2
    if show_plot:
        show_2D_array('Acquisition data', acq_array[0,z,:,:])

    # compute randoms
    print('estimating randoms, please wait...')
    randoms = lm2sino.estimate_randoms()
    rnd_array = randoms.as_array()
    if show_plot:
        show_2D_array('Randoms', rnd_array[0,z,:,:])
コード例 #4
0
def main():

    # output goes to files
    msg_red = MessageRedirector('info.txt', 'warn.txt', 'errr.txt')

    # create acquisition model
    acq_model = AcquisitionModelUsingRayTracingMatrix()

    # PET acquisition data to be read from the file specified by --file option
    print('raw data: %s' % raw_data_file)
    acq_data = AcquisitionData(raw_data_file)

    # create filter that zeroes the image outside a cylinder of the same
    # diameter as the image xy-section size
    filter = TruncateToCylinderProcessor()

    # create initial image estimate
    image_size = (31, 111, 111)
    voxel_size = (3.375, 3, 3) # voxel sizes are in mm
    image = ImageData()
    image.initialise(image_size, voxel_size)
    image.fill(1.0)

    # create prior
    prior = QuadraticPrior()
    prior.set_penalisation_factor(0.5)
    prior.set_up(image)

    # create objective function
    obj_fun = make_Poisson_loglikelihood(acq_data)
    obj_fun.set_acquisition_model(acq_model)
    obj_fun.set_num_subsets(num_subsets)
    obj_fun.set_up(image)

    # reconstruct using your own SIRF-based implementation of OSMAPOSL
    image = my_osmaposl \
        (image, obj_fun, prior, filter, num_subsets, num_subiterations)

    if show_plot:
        # show reconstructed image at z = 20
        image_array = image.as_array()
        show_2D_array('Reconstructed image at z = 20', image_array[20,:,:])
コード例 #5
0
def main():

    # direct all engine's messages to files
    msg_red = PET.MessageRedirector('info.txt', 'warn.txt', 'errr.txt')

    PET.AcquisitionData.set_storage_scheme('memory')

    # Create the Scatter Estimator
    # We can use a STIR parameter file like this
    # par_file_path = os.path.join(os.path.dirname(__file__), '..', '..', 'parameter_files')
    # se = PET.ScatterEstimator(PET.existing_filepath(par_file_path, 'scatter_estimation.par'))
    # However, we will just use all defaults here, and set variables below.
    se = PET.ScatterEstimator()

    prompts = PET.AcquisitionData(raw_data_file)
    se.set_input(prompts)
    se.set_attenuation_image(PET.ImageData(mu_map_file))
    if randoms_data_file is None:
        randoms = None
    else:
        randoms = PET.AcquisitionData(randoms_data_file)
        se.set_randoms(randoms)
    if not(norm_file is None):
        se.set_asm(PET.AcquisitionSensitivityModel(norm_file))
    if not(acf_file is None):
        se.set_attenuation_correction_factors(PET.AcquisitionData(acf_file))
    # could set number of iterations if you want to
    se.set_num_iterations(1)
    print("number of scatter iterations that will be used: %d" % se.get_num_iterations())
    se.set_output_prefix(output_prefix)
    se.set_up()
    se.process()
    scatter_estimate = se.get_output()

    ## show estimated scatter data
    scatter_estimate_as_array = scatter_estimate.as_array()
    show_2D_array('Scatter estimate', scatter_estimate_as_array[0, 0, :, :])

    ## let's draw some profiles to check
    # we will average over all sinograms to reduce noise
    PET_plot_functions.plot_sinogram_profile(prompts, randoms=randoms, scatter=scatter_estimate)
コード例 #6
0
def main():

    ## AcquisitionData.set_storage_scheme('mem')

    # no info printing from the engine, warnings and errors sent to stdout
    # msg_red = MessageRedirector()
    # output goes to files
    msg_red = sirf.STIR.MessageRedirector('info.txt', 'warn.txt', 'errr.txt')

    # raw data to be used as a template for the acquisition model
    acq_template = sirf.STIR.AcquisitionData(raw_data_file)

    # create image with suitable sizes
    image = acq_template.create_uniform_image()
    create_sample_image(image)
    image.write("simulated_image.hv")

    # z-pixel coordinate of the xy-cross-section to show
    z = image.dimensions()[0]//2

    # show the phantom image
    image_array = image.as_array()
    show_2D_array('Phantom image', image_array[z,:,:])

    # select acquisition model that implements the geometric
    # forward projection by a ray tracing matrix multiplication
    acq_model_matrix = sirf.STIR.SPECTUBMatrix();
    acq_model = sirf.STIR.AcquisitionModelUsingMatrix(acq_model_matrix)

    # require same number slices and equal z-sampling for projection data & image
    image = image.zoom_image(zooms=(0.5, 1.0, 1.0), size=(12, -1, -1))
    print('projecting image...')
    # project the image to obtain simulated acquisition data
    # data from raw_data_file is used as a template
    acq_model.set_up(acq_template, image)
    simulated_data = acq_template.get_uniform_copy()
    acq_model.forward(image, 0, 1, simulated_data)
    # simulated_data = acq_model.forward(image, 0, 4)
    if output_file is not None:
        simulated_data.write(output_file)

    # show simulated acquisition data
    simulated_data_as_array = simulated_data.as_array()
    middle_slice=simulated_data_as_array.shape[0]//2
    show_2D_array('Forward projection', simulated_data_as_array[0, middle_slice,:,:])

    print('backprojecting the forward projection...')
    # backproject the computed forward projection
    back_projected_image = acq_model.backward(simulated_data, 0, 1)

    back_projected_image_as_array = back_projected_image.as_array()
    show_2D_array('Backprojection', back_projected_image_as_array[z,:,:])
コード例 #7
0
def main():
    ##    PET.AcquisitionData.set_storage_scheme('memory')

    # no info printing from the engine, warnings and errors sent to stdout
    msg_red = PET.MessageRedirector()

    # Create a template Acquisition Model
    #acq_template = AcquisitionData('Siemens mMR', 1, 0, 1)
    acq_template = PET.AcquisitionData(
        acq_template_filename)  #q.get_uniform_copy()

    # create the attenuation image
    atten_image = PET.ImageData(acq_template)
    image_size = atten_image.dimensions()
    voxel_size = atten_image.voxel_sizes()

    # create a cylindrical water phantom
    water_cyl = PET.EllipticCylinder()
    water_cyl.set_length(image_size[0] * voxel_size[0])
    water_cyl.set_radii((image_size[1]*voxel_size[1]*0.25, \
                     image_size[2]*voxel_size[2]*0.25))
    water_cyl.set_origin((image_size[0] * voxel_size[0] * 0.5, 0, 0))

    # add the shape to the image
    atten_image.add_shape(water_cyl, scale=9.687E-02)

    # z-pixel coordinate of the xy-crossection to show
    z = int(image_size[0] * 0.5)

    # show the phantom image
    atten_image_array = atten_image.as_array()
    show_2D_array('Attenuation image', atten_image_array[z, :, :])

    # Create the activity image
    act_image = atten_image.clone()
    act_image.fill(0.0)

    # create the activity cylinder
    act_cyl = PET.EllipticCylinder()
    act_cyl.set_length(image_size[0] * voxel_size[0])
    act_cyl.set_radii((image_size[1] * voxel_size[1] * 0.125, \
                         image_size[2] * voxel_size[2] * 0.125))
    act_cyl.set_origin((0, image_size[1] * voxel_size[1] * 0.06, \
                          image_size[2] * voxel_size[2] * 0.06))

    # add the shape to the image
    act_image.add_shape(act_cyl, scale=1)

    # z-pixel coordinate of the xy-crossection to show
    z = int(image_size[0] * 0.5)

    # show the phantom image
    act_image_array = act_image.as_array()
    show_2D_array('Activity image', act_image_array[z, :, :])

    # Create the Single Scatter Simulation model
    sss = PET.SingleScatterSimulator()

    # Set the attenuation image
    sss.set_attenuation_image(atten_image)

    # set-up the scatter simulator
    sss.set_up(acq_template, act_image)
    # Simulate!
    sss_data = sss.forward(act_image)

    # show simulated scatter data
    simulated_scatter_as_array = sss_data.as_array()
    show_2D_array('scatter simulation', simulated_scatter_as_array[0, 0, :, :])

    sss_data.write(output_file)

    ## let's also compute the unscattered counts (at the same low resolution) and compare

    acq_model = PET.AcquisitionModelUsingRayTracingMatrix()
    asm = PET.AcquisitionSensitivityModel(atten_image, acq_model)
    acq_model.set_acquisition_sensitivity(asm)

    acq_model.set_up(acq_template, act_image)
    #unscattered_data = acq_template.get_uniform_copy()
    unscattered_data = acq_model.forward(act_image)
    simulated_unscatter_as_array = unscattered_data.as_array()
    show_2D_array('unscattered simulation',
                  simulated_unscatter_as_array[0, 0, :, :])

    plt.figure()
    ax = plt.subplot(111)
    plt.plot(simulated_unscatter_as_array[0, 4, 0, :], label='unscattered')
    plt.plot(simulated_scatter_as_array[0, 4, 0, :], label='scattered')
    ax.legend()
    plt.show()
コード例 #8
0
def main():

    print(scanner_names())

    ##    AcquisitionData.set_storage_scheme('mem')

    # no info printing from the engine, warnings and errors sent to stdout
    msg_red = MessageRedirector()
    # output goes to files
    ##    msg_red = MessageRedirector('info.txt', 'warn.txt', 'errr.txt')

    # raw data to be used as a template for the acquisition model
    acq_template = AcquisitionData(raw_data_file)

    # create an empty image
    image = acq_template.create_uniform_image(0.0, xy=111)
    image_size = image.dimensions()
    print('image size: %d by %d by %d' % image_size)

    # create a shape
    shape = EllipticCylinder()
    shape.set_length(400)
    shape.set_radii((40, 100))
    shape.set_origin((10, 60, 0))

    # add the shape to the image
    image.add_shape(shape, scale=1)

    # add another shape
    shape.set_radii((30, 30))
    shape.set_origin((10, -30, 60))
    image.add_shape(shape, scale=1.5)

    # add another shape
    shape.set_origin((10, -30, -60))
    image.add_shape(shape, scale=0.75)

    # apply Gaussian filter
    filter = SeparableGaussianImageFilter()
    filter.set_fwhms((10, 20, 30))
    filter.set_max_kernel_sizes((10, 10, 2))
    filter.set_normalise()
    filter.set_up(image)
    filter.apply(image)

    # z-pixel coordinate of the xy-crossection to show
    z = int(image_size[0] / 2)

    if show_plot:
        # show the phantom image
        image_array = image.as_array()
        show_2D_array('Phantom image', image_array[z, :, :])

    # select acquisition model that implements the geometric
    # forward projection by a ray tracing matrix multiplication
    acq_model = AcquisitionModelUsingRayTracingMatrix()

    # testing bin efficiencies
    bin_eff = acq_template.clone()
    bin_eff.fill(beff)
    bin_eff_arr = bin_eff.as_array()
    # As an example, if bin efficiencies are non-trivial, set a portion of them to zero;
    # this should zero the corresponding portion of forward projection
    # and 'damage' the backprojection making it look less like the
    # actual image
    if beff != 1:
        bin_eff_arr[0, :, 10:50, :] = 0
    if show_plot:
        show_2D_array('Bin efficiencies', bin_eff_arr[0, 0, :, :])
    bin_eff.fill(bin_eff_arr)

    asm = AcquisitionSensitivityModel(bin_eff)
    acq_model.set_acquisition_sensitivity(asm)

    # As an example, add both an additive term and background term
    # (you normally wouldn't do this for real data)
    add = acq_template.clone()
    add.fill(addv)
    acq_model.set_additive_term(add)

    bck = acq_template.clone()
    bck.fill(back)
    acq_model.set_background_term(bck)

    print('projecting image...')
    # project the image to obtain simulated acquisition data
    # data from raw_data_file is used as a template
    acq_model.set_up(acq_template, image)
    simulated_data = acq_template.get_uniform_copy()
    acq_model.forward(image, 0, 4, simulated_data)
    #    simulated_data = acq_model.forward(image, 0, 4)
    if output_file is not None:
        simulated_data.write(output_file)

    print(
        '\n--- Computing the norm of the linear part A of acquisition model...'
    )
    acqm_norm = acq_model.norm()
    image_norm = image.norm()
    acqd_norm = simulated_data.norm()
    print('\n--- The computed norm is |A| = %f, checking...' % acqm_norm)
    print('    image data x norm: |x| = %f' % image_norm)
    print('    forward projected data A x norm: |A x| = %f' % acqd_norm)
    acqd_bound = acqm_norm * image_norm
    msg = '    |A x| must be less than or equal to |A||x| = %f'
    if acqd_norm <= acqd_bound:
        msg += ' - ok\n'
    else:
        msg += ' - ???\n'
    print(msg % acqd_bound)

    if show_plot:
        # show simulated acquisition data
        simulated_data_as_array = simulated_data.as_array()
        show_2D_array('Forward projection (subset 0/4)',
                      simulated_data_as_array[0, 0, :, :])

    print('backprojecting the forward projection...')
    # backproject the computed forward projection
    # note that the backprojection takes the acquisition sensitivy model asm into account as well
    back_projected_image = acq_model.backward(simulated_data, 0, 4)
    back_projected_image_as_array = back_projected_image.as_array()
    if show_plot:
        show_2D_array('Backprojection', back_projected_image_as_array[z, :, :])

    # backproject again, this time into pre-allocated image
    back_projected_image.fill(0.0)
    acq_model.backward(simulated_data, 0, 4, out=back_projected_image)
    back_projected_image_as_array = back_projected_image.as_array()
    if show_plot:
        msg = 'Backprojection into pre-allocated image'
        show_2D_array(msg, back_projected_image_as_array[z, :, :])

    # do same with pre-smoothing (often used for resolution modelling)
    print('Using some PSF modelling for comparison')
    smoother = SeparableGaussianImageFilter()
    smoother.set_fwhms((6, 11, 12))
    acq_model.set_image_data_processor(smoother)
    acq_model.set_up(acq_template, image)
    simulated_data_PSF = acq_template.get_uniform_copy()
    acq_model.forward(image, 0, 4, simulated_data_PSF)
    if show_plot:
        simulated_data_PSF_as_array = simulated_data_PSF.as_array()
        plt.figure()
        plt.plot(simulated_data_as_array[0, 0, 0, :], label="no PSF")
        plt.plot(simulated_data_PSF_as_array[0, 0, 0, :], label="PSF")
        plt.title(
            'Diff Forward projection without/ with smoothing (first view)')
        plt.legend()
    # backprojection
    back_projected_image_PSF = acq_model.backward(simulated_data, 0, 4)
    if show_plot:
        back_projected_image_PSF_as_array = back_projected_image_PSF.as_array()
        y = back_projected_image_as_array.shape[1] // 2
        plt.figure()
        plt.plot(back_projected_image_as_array[z, y, :], label="no PSF")
        plt.plot(back_projected_image_PSF_as_array[z, y, :], label="PSF")
        plt.title(
            'Diff Back projection without/ with smoothing (central horizontal line)'
        )
        plt.legend()

    # direct is alias for the forward method for a linear AcquisitionModel
    # raises error if the AcquisitionModel is not linear.
    try:
        acq_model.num_subsets = 4
        acq_model.direct(image, simulated_data)
    except error as err:
        print('%s' % err.value)
        print('Extracting the linear acquisition model...')
        lin_acq_model = acq_model.get_linear_acquisition_model()
        lin_acq_model.direct(image, simulated_data)

    if show_plot:
        # show simulated acquisition data
        simulated_data_as_array_direct = simulated_data.as_array()
        show_2D_array('Direct projection',
                      simulated_data_as_array_direct[0, 0, :, :])

    # adjoint is an alias for the backward method for a linear AcquisitionModel
    # raises error if the AcquisitionModel is not linear.
    try:
        back_projected_image_adj = acq_model.adjoint(simulated_data)
    except error as err:
        print('%s' % err.value)
        print('Extracting the linear acquisition model...')
        lin_acq_model = acq_model.get_linear_acquisition_model()
        back_projected_image_adj = lin_acq_model.adjoint(simulated_data)

    if show_plot:
        back_projected_image_as_array_adj = back_projected_image_adj.as_array()
        show_2D_array('Adjoint projection',
                      back_projected_image_as_array_adj[z, :, :])
コード例 #9
0
ファイル: SPECT_OSEM.py プロジェクト: danieldeidda/SIRF
def main():

    ## AcquisitionData.set_storage_scheme('mem')

    # no info printing from the engine, warnings and errors sent to stdout
    # msg_red = MessageRedirector()
    # output goes to files
    msg_red = sirf.STIR.MessageRedirector('info.txt', 'warn.txt', 'errr.txt')

    # raw data to be used as a template for the acquisition model
    acq_template = sirf.STIR.AcquisitionData(raw_data_file)

    # create image with suitable sizes
    image = acq_template.create_uniform_image()
    create_sample_image(image)
    image.write("simulated_image.hv")

    # create attenuation image
    uMap = acq_template.create_uniform_image()
    create_sample_image(uMap, attenuation=True)
    uMap.write("simulated_uMap.hv")

    # z-pixel coordinate of the xy-cross-section to show
    z = image.dimensions()[0] // 2

    # show the phantom image
    image_array = image.as_array()
    show_2D_array('Phantom image', image_array[z, :, :])

    # show the attenuation image
    uMap_array = uMap.as_array()
    show_2D_array('Attenuation image', uMap_array[z, :, :])

    # require same number slices and equal z-sampling for projection data & image
    image = image.zoom_image(zooms=(0.5, 1.0, 1.0), size=(12, -1, -1))
    uMap = uMap.zoom_image(zooms=(0.5, 1.0, 1.0), size=(12, -1, -1))

    # select acquisition model that implements the geometric
    # forward projection by a ray tracing matrix multiplication
    acq_model_matrix = sirf.STIR.SPECTUBMatrix()
    acq_model_matrix.set_attenuation_image(uMap)  # add attenuation
    acq_model = sirf.STIR.AcquisitionModelUsingMatrix(acq_model_matrix)

    print('projecting image...')
    # project the image to obtain simulated acquisition data
    # data from raw_data_file is used as a template
    acq_model.set_up(acq_template, image)
    simulated_data = acq_template.get_uniform_copy()
    acq_model.forward(image, 0, 1, simulated_data)
    if output_file is not None:
        simulated_data.write(output_file)

    # show simulated acquisition data
    simulated_data_as_array = simulated_data.as_array()
    middle_slice = simulated_data_as_array.shape[0] // 2
    show_2D_array('Forward projection',
                  simulated_data_as_array[0, middle_slice, :, :])

    # create noisy data
    noisy_data = simulated_data.clone()
    noisy_data_as_array = np.random.poisson(simulated_data.as_array())
    noisy_data.fill(noisy_data_as_array)
    show_2D_array('Forward projection with added noise',
                  noisy_data_as_array[0, middle_slice, :, :])

    # create objective function
    obj_fun = sirf.STIR.make_Poisson_loglikelihood(noisy_data)
    obj_fun.set_acquisition_model(acq_model)

    # create OSEM reconstructor object
    num_subsets = 30  # number of subsets for OSEM reconstruction
    num_subiters = 60  #number of subiterations (i.e two full iterations)
    OSEM_reconstructor = sirf.STIR.OSMAPOSLReconstructor()
    OSEM_reconstructor.set_objective_function(obj_fun)
    OSEM_reconstructor.set_num_subsets(num_subsets)
    OSEM_reconstructor.set_num_subiterations(num_subiters)

    # create initialisation image and set up reconstructor
    init_image = make_cylindrical_FOV(image.get_uniform_copy(1))
    OSEM_reconstructor.set_up(init_image)

    # Reconstruct and show reconstructed image
    OSEM_reconstructor.reconstruct(init_image)
    out_image = OSEM_reconstructor.get_current_estimate()
    out_image_array = out_image.as_array()
    show_2D_array('Reconstructed image', out_image_array[z, :, :])
コード例 #10
0
def main():

    ###########################################################################
    # Parse input files
    ###########################################################################

    if trans_pattern is None:
        raise AssertionError("--trans missing")
    if sino_pattern is None:
        raise AssertionError("--sino missing")
    trans_files = sorted(glob(trans_pattern))
    sino_files = sorted(glob(sino_pattern))
    attn_files = sorted(glob(attn_pattern))
    rand_files = sorted(glob(rand_pattern))

    num_ms = len(sino_files)
    # Check some sinograms found
    if num_ms == 0:
        raise AssertionError("No sinograms found!")
    # Should have as many trans as sinos
    if num_ms != len(trans_files):
        raise AssertionError("#trans should match #sinos. "
                             "#sinos = " + str(num_ms) + ", #trans = " +
                             str(len(trans_files)))
    # If any rand, check num == num_ms
    if len(rand_files) > 0 and len(rand_files) != num_ms:
        raise AssertionError("#rand should match #sinos. "
                             "#sinos = " + str(num_ms) + ", #rand = " +
                             str(len(rand_files)))

    # For attn, there should be 0, 1 or num_ms images
    if len(attn_files) > 1 and len(attn_files) != num_ms:
        raise AssertionError("#attn should be 0, 1 or #sinos")

    ###########################################################################
    # Read input
    ###########################################################################

    if trans_type == "tm":
        trans = [reg.AffineTransformation(file) for file in trans_files]
    elif trans_type == "disp":
        trans = [
            reg.NiftiImageData3DDisplacement(file) for file in trans_files
        ]
    elif trans_type == "def":
        trans = [reg.NiftiImageData3DDeformation(file) for file in trans_files]
    else:
        raise error("Unknown transformation type")

    sinos_raw = [pet.AcquisitionData(file) for file in sino_files]
    attns = [pet.ImageData(file) for file in attn_files]
    rands = [pet.AcquisitionData(file) for file in rand_files]

    # Loop over all sinograms
    sinos = [0] * num_ms
    for ind in range(num_ms):
        # If any sinograms contain negative values
        # (shouldn't be the case), set them to 0
        sino_arr = sinos_raw[ind].as_array()
        if (sino_arr < 0).any():
            print("Input sinogram " + str(ind) +
                  " contains -ve elements. Setting to 0...")
            sinos[ind] = sinos_raw[ind].clone()
            sino_arr[sino_arr < 0] = 0
            sinos[ind].fill(sino_arr)
        else:
            sinos[ind] = sinos_raw[ind]
        # If rebinning is desired
        segs_to_combine = 1
        if args['--numSegsToCombine']:
            segs_to_combine = int(args['--numSegsToCombine'])
        views_to_combine = 1
        if args['--numViewsToCombine']:
            views_to_combine = int(args['--numViewsToCombine'])
        if segs_to_combine * views_to_combine > 1:
            sinos[ind] = sinos[ind].rebin(segs_to_combine, views_to_combine)
            # only print first time
            if ind == 0:
                print(f"Rebinned sino dimensions: {sinos[ind].dimensions()}")

    ###########################################################################
    # Initialise recon image
    ###########################################################################

    if initial_estimate:
        image = pet.ImageData(initial_estimate)
    else:
        # Create image based on ProjData
        image = sinos[0].create_uniform_image(0.0, (nxny, nxny))
        # If using GPU, need to make sure that image is right size.
        if use_gpu:
            dim = (127, 320, 320)
            spacing = (2.03125, 2.08626, 2.08626)
        # elif non-default spacing desired
        elif args['--dxdy']:
            dim = image.dimensions()
            dxdy = float(args['--dxdy'])
            spacing = (image.voxel_sizes()[0], dxdy, dxdy)
        if use_gpu or args['--dxdy']:
            image.initialise(dim=dim, vsize=spacing)
            image.fill(0.0)

    ###########################################################################
    # Set up resamplers
    ###########################################################################

    resamplers = [get_resampler(image, trans=tran) for tran in trans]

    ###########################################################################
    # Resample attenuation images (if necessary)
    ###########################################################################

    resampled_attns = None
    if len(attns) > 0:
        resampled_attns = [0] * num_ms
        # if using GPU, dimensions of attn and recon images have to match
        ref = image if use_gpu else None
        for i in range(len(attns)):
            # if we only have 1 attn image, then we need to resample into
            # space of each gate. However, if we have num_ms attn images, then
            # assume they are already in the correct position, so use None as
            # transformation.
            tran = trans[i] if len(attns) == 1 else None
            # If only 1 attn image, then resample that. If we have num_ms attn
            # images, then use each attn image of each frame.
            attn = attns[0] if len(attns) == 1 else attns[i]
            resam = get_resampler(attn, ref=ref, trans=tran)
            resampled_attns[i] = resam.forward(attn)

    ###########################################################################
    # Set up acquisition models
    ###########################################################################

    print("Setting up acquisition models...")
    if not use_gpu:
        acq_models = num_ms * [pet.AcquisitionModelUsingRayTracingMatrix()]
    else:
        acq_models = num_ms * [pet.AcquisitionModelUsingNiftyPET()]
        for acq_model in acq_models:
            acq_model.set_use_truncation(True)
            acq_model.set_cuda_verbosity(verbosity)

    # If present, create ASM from ECAT8 normalisation data
    asm_norm = None
    if norm_file:
        asm_norm = pet.AcquisitionSensitivityModel(norm_file)

    # Loop over each motion state
    for ind in range(num_ms):
        # Create attn ASM if necessary
        asm_attn = None
        if resampled_attns:
            asm_attn = get_asm_attn(sinos[ind], resampled_attns[i],
                                    acq_models[ind])

        # Get ASM dependent on attn and/or norm
        asm = None
        if asm_norm and asm_attn:
            if ind == 0:
                print("ASM contains norm and attenuation...")
            asm = pet.AcquisitionSensitivityModel(asm_norm, asm_attn)
        elif asm_norm:
            if ind == 0:
                print("ASM contains norm...")
            asm = asm_norm
        elif asm_attn:
            if ind == 0:
                print("ASM contains attenuation...")
            asm = asm_attn
        if asm:
            acq_models[ind].set_acquisition_sensitivity(asm)

        if len(rands) > 0:
            acq_models[ind].set_background_term(rands[ind])

        # Set up
        acq_models[ind].set_up(sinos[ind], image)

    ###########################################################################
    # Set up reconstructor
    ###########################################################################

    print("Setting up reconstructor...")

    # Create composition operators containing acquisition models and resamplers
    C = [
        CompositionOperator(am, res, preallocate=True)
        for am, res in zip(*(acq_models, resamplers))
    ]

    # Configure the PDHG algorithm
    if args['--normK'] and not args['--onlyNormK']:
        normK = float(args['--normK'])
    else:
        kl = [KullbackLeibler(b=sino, eta=(sino * 0 + 1e-5)) for sino in sinos]
        f = BlockFunction(*kl)
        K = BlockOperator(*C)
        # Calculate normK
        print("Calculating norm of the block operator...")
        normK = K.norm(iterations=10)
        print("Norm of the BlockOperator ", normK)
        if args['--onlyNormK']:
            exit(0)

    # Optionally rescale sinograms and BlockOperator using normK
    scale_factor = 1. / normK if args['--normaliseDataAndBlock'] else 1.0
    kl = [
        KullbackLeibler(b=sino * scale_factor, eta=(sino * 0 + 1e-5))
        for sino in sinos
    ]
    f = BlockFunction(*kl)
    K = BlockOperator(*C) * scale_factor

    # If preconditioned
    if precond:

        def get_nonzero_recip(data):
            """Get the reciprocal of a datacontainer. Voxels where input == 0
            will have their reciprocal set to 1 (instead of infinity)"""
            inv_np = data.as_array()
            inv_np[inv_np == 0] = 1
            inv_np = 1. / inv_np
            data.fill(inv_np)

        tau = K.adjoint(K.range_geometry().allocate(1))
        get_nonzero_recip(tau)

        tmp_sigma = K.direct(K.domain_geometry().allocate(1))
        sigma = 0. * tmp_sigma
        get_nonzero_recip(sigma[0])

        def precond_proximal(self, x, tau, out=None):
            """Modify proximal method to work with preconditioned tau"""
            pars = {
                'algorithm':
                FGP_TV,
                'input':
                np.asarray(x.as_array() / tau.as_array(), dtype=np.float32),
                'regularization_parameter':
                self.lambdaReg,
                'number_of_iterations':
                self.iterationsTV,
                'tolerance_constant':
                self.tolerance,
                'methodTV':
                self.methodTV,
                'nonneg':
                self.nonnegativity,
                'printingOut':
                self.printing
            }

            res, info = regularisers.FGP_TV(pars['input'],
                                            pars['regularization_parameter'],
                                            pars['number_of_iterations'],
                                            pars['tolerance_constant'],
                                            pars['methodTV'], pars['nonneg'],
                                            self.device)
            if out is not None:
                out.fill(res)
            else:
                out = x.copy()
                out.fill(res)
            out *= tau
            return out

        FGP_TV.proximal = precond_proximal
        print("Will run proximal with preconditioned tau...")

    # If not preconditioned
    else:
        sigma = float(args['--sigma'])
        # If we need to calculate default tau
        if args['--tau']:
            tau = float(args['--tau'])
        else:
            tau = 1 / (sigma * normK**2)

    if regularisation == 'none':
        G = IndicatorBox(lower=0)
    elif regularisation == 'FGP_TV':
        r_iterations = float(args['--reg_iters'])
        r_tolerance = 1e-7
        r_iso = 0
        r_nonneg = 1
        r_printing = 0
        device = 'gpu' if use_gpu else 'cpu'
        G = FGP_TV(r_alpha, r_iterations, r_tolerance, r_iso, r_nonneg,
                   r_printing, device)
    else:
        raise error("Unknown regularisation")

    if precond:

        def PDHG_new_update(self):
            """Modify the PDHG update to allow preconditioning"""
            # save previous iteration
            self.x_old.fill(self.x)
            self.y_old.fill(self.y)

            # Gradient ascent for the dual variable
            self.operator.direct(self.xbar, out=self.y_tmp)
            self.y_tmp *= self.sigma
            self.y_tmp += self.y_old

            self.f.proximal_conjugate(self.y_tmp, self.sigma, out=self.y)

            # Gradient descent for the primal variable
            self.operator.adjoint(self.y, out=self.x_tmp)
            self.x_tmp *= -1 * self.tau
            self.x_tmp += self.x_old

            self.g.proximal(self.x_tmp, self.tau, out=self.x)

            # Update
            self.x.subtract(self.x_old, out=self.xbar)
            self.xbar *= self.theta
            self.xbar += self.x

        PDHG.update = PDHG_new_update

    # Get filename
    outp_file = outp_prefix
    if descriptive_fname:
        if len(attn_files) > 0:
            outp_file += "_wAC"
        if norm_file:
            outp_file += "_wNorm"
        if use_gpu:
            outp_file += "_wGPU"
        outp_file += "_Reg-" + regularisation
        if regularisation == 'FGP_TV':
            outp_file += "-alpha" + str(r_alpha)
            outp_file += "-riters" + str(r_iterations)
        if args['--normK']:
            outp_file += '_userNormK' + str(normK)
        else:
            outp_file += '_calcNormK' + str(normK)
        if args['--normaliseDataAndBlock']:
            outp_file += '_wDataScale'
        else:
            outp_file += '_noDataScale'
        if not precond:
            outp_file += "_sigma" + str(sigma)
            outp_file += "_tau" + str(tau)
        else:
            outp_file += "_wPrecond"
        outp_file += "_nGates" + str(len(sino_files))
        if resamplers is None:
            outp_file += "_noMotion"

    pdhg = PDHG(f=f,
                g=G,
                operator=K,
                sigma=sigma,
                tau=tau,
                max_iteration=num_iters,
                update_objective_interval=update_obj_fn_interval,
                x_init=image,
                log_file=outp_file + ".log")

    def callback_save(iteration, objective_value, solution):
        """Callback function to save images"""
        if (iteration + 1) % save_interval == 0:
            out = solution if not nifti else reg.NiftiImageData(solution)
            out.write(outp_file + "_iters" + str(iteration + 1))

    pdhg.run(iterations=num_iters,
             callback=callback_save,
             verbose=True,
             very_verbose=True)

    if visualisations:
        # show reconstructed image
        out = pdhg.get_output()
        out_arr = out.as_array()
        z = out_arr.shape[0] // 2
        show_2D_array('Reconstructed image', out.as_array()[z, :, :])
        pylab.show()
コード例 #11
0
def main():

    # engine's messages go to files, except error messages, which go to stdout
    msg_red = MessageRedirector('info.txt', 'warn.txt')

    acq_template = AcquisitionData(templ_file)
    ##    # create acquisition data from scanner parameters to be used as a template
    ##    print('creating Siemens_mMR acquisition data...')
    ##    acq_template = AcquisitionData('Siemens_mMR')
    ##    acq_dim = acq_template.dimensions()
    ##    print('acquisition data dimensions: %d sinograms, %d views, %d tang. pos.' \
    ##          % acq_dim)
    ##    # rebin to reduce the acquisition data size
    ##    print('rebinning...')
    ##    acq_template = acq_template.rebin(15)
    acq_dim = acq_template.dimensions()
    print('acquisition data dimensions: ' + \
          '%d TOF bins %d (non-TOF) sinograms, %d views, %d tang. pos.' \
          % acq_dim)

    # create image of dimensions and voxel sizes compatible with the scanner
    # geometry (stored in the AcquisitionData object ad)
    # and initialize each voxel to 1.0
    print('creating compatible phantom')
    image = acq_template.create_uniform_image()
    # show the image
    nz, ny, nx = image.dimensions()
    vz, vy, vx = image.voxel_sizes()
    print('phantom dimensions: %dx%dx%d' % (nz, ny, nx))
    print('phantom voxel sizes: %fx%fx%f' % (vz, vy, vx))
    image_size = (int(nz), 111, 111)
    voxel_size = (float(vz), 3.0, 3.0)
    image = ImageData()
    image.initialise(image_size, voxel_size)

    # create a shape
    shape = EllipticCylinder()
    shape.set_length(400)
    shape.set_radii((40, 100))
    shape.set_origin((10, 60, 0))

    # add the shape to the image
    image.add_shape(shape, scale=1)

    # add another shape
    shape.set_radii((30, 30))
    shape.set_origin((10, -30, 60))
    image.add_shape(shape, scale=1.5)

    # add another shape
    shape.set_origin((10, -30, -60))
    image.add_shape(shape, scale=0.75)

    image_array = image.as_array()
    z = int(image_array.shape[0] / 2)
    if show_plot:
        show_2D_array('Phantom', image_array[z, :, :])

    # select acquisition model that implements the geometric
    # forward projection by a ray tracing matrix multiplication
    acq_model = AcquisitionModelUsingRayTracingMatrix()
    print('setting up the acquisition model...')
    acq_model.set_up(acq_template, image)
    # project the image to obtain simulated acquisition data
    print('projecting the phantom to create simulated acquisition data...')
    simulated_data = acq_model.forward(image)

    # copy the acquisition data into a Python array
    acq_array = simulated_data.as_array()
    acq_dim = acq_array.shape
    ##    print('acquisition data dimensions: %dx%dx%d' % acq_dim)
    z = acq_dim[1] // 2
    if show_plot:
        show_2D_array('Simulated acquisition data', acq_array[0, z, :, :])

    # write acquisition data and image to files
    print('writing acquisition data...')
    simulated_data.write(acq_file)
    print('writing image...')
    image.write(img_file)

    # read acquisition data and image from files
    acq_data = AcquisitionData('simulated_data.hs')
    acq_array = acq_data.as_array()
    acq_dim = acq_array.shape
    ##    print('acquisition data dimensions: %dx%dx%d' % acq_dim)
    z = acq_dim[1] // 2
    if show_plot:
        show_2D_array('Simulated acquisition data', acq_array[0, z, :, :])

    # show the image again
    img = ImageData()
    img.read_from_file('phantom.hv')
    image_array = img.as_array()
    ##    print('phantom dimensions: %dx%dx%d' % image_array.shape[2::-1])
    z = int(image_array.shape[0] / 2)
    if show_plot:
        show_2D_array('Phantom', image_array[z, :, :])
コード例 #12
0
def main():

    # direct all engine's messages to files
    msg_red = MessageRedirector('info.txt', 'warn.txt', 'errr.txt')

    # select acquisition data storage scheme
    AcquisitionData.set_storage_scheme(storage)

    # PET acquisition data to be read from this file
    raw_data_file = existing_filepath(data_path, data_file)
    print('raw data: %s' % raw_data_file)
    acq_data = AcquisitionData(raw_data_file)

    # copy the acquisition data into a Python array and display it
    acq_array = acq_data.as_array()
    acq_dim = acq_array.shape
    z = acq_dim[1]//2
    if show_plot:
        show_2D_array('Acquisition data', acq_array[0,z,:,:])

    # create bin efficiencies sinograms
    bin_eff = acq_data.clone()
    bin_eff.fill(2.0)
    bin_eff_arr = bin_eff.as_array()
    bin_eff_arr[0,:,10:50,:] = 0
    if show_plot:
        show_2D_array('Bin efficiencies', bin_eff_arr[0,z,:,:])
    bin_eff.fill(bin_eff_arr)

    # create acquisition sensitivity model from bin efficiencies
    asm = AcquisitionSensitivityModel(bin_eff)

    # apply normalization to acquisition data
    ad = acq_data.clone()
    asm.set_up(ad)
    asm.unnormalise(ad)
    ad_array = ad.as_array()
    if show_plot:
        show_2D_array('Normalized acquisition data', ad_array[0,z,:,:])

    # create another bin efficiencies sinograms
    bin_eff_arr[0,:,10:50,:] = 2.0
    bin_eff_arr[0,:,60:80,:] = 0
    if show_plot:
        show_2D_array('Another bin efficiencies', bin_eff_arr[0,z,:,:])
    bin_eff2 = acq_data.clone()
    bin_eff2.fill(bin_eff_arr)

    # create another acquisition sensitivity model from bin efficiencies
    asm2 = AcquisitionSensitivityModel(bin_eff2)

    # chain the two models
    asm12 = AcquisitionSensitivityModel(asm, asm2)
    asm12.set_up(acq_data)

    # apply the chain of models to acquisition data
    ad = acq_data.clone()
    asm12.unnormalise(ad)
    ad_array = ad.as_array()
    if show_plot:
        show_2D_array('Chain-normalized acquisition data', ad_array[0,z,:,:])