def test_PDHG_strongly_convex_gamma_g(self):

        ig = ImageGeometry(3,3)
        data = ig.allocate('random')

        f = L2NormSquared(b=data)
        g = L2NormSquared()
        operator = IdentityOperator(ig)

        # sigma, tau 
        sigma = 1.0
        tau  = 1.0        

        pdhg = PDHG(f=f, g=g, operator=operator, sigma = sigma, tau=tau,
                    max_iteration=5, gamma_g=0.5)
        pdhg.run(1, verbose=0)
        self.assertAlmostEquals(pdhg.theta, 1.0/ np.sqrt(1 + 2 * pdhg.gamma_g * tau))
        self.assertAlmostEquals(pdhg.tau, tau * pdhg.theta)
        self.assertAlmostEquals(pdhg.sigma, sigma / pdhg.theta)
        pdhg.run(4, verbose=0)
        self.assertNotEqual(pdhg.sigma, sigma)
        self.assertNotEqual(pdhg.tau, tau)  

        # check negative strongly convex constant
        with self.assertRaises(ValueError):
            pdhg = PDHG(f=f, g=g, operator=operator, sigma = sigma, tau=tau,
                    max_iteration=5, gamma_g=-0.5)  
        

        # check strongly convex constant not a number
        with self.assertRaises(ValueError):
            pdhg = PDHG(f=f, g=g, operator=operator, sigma = sigma, tau=tau,
                    max_iteration=5, gamma_g="-0.5")  
Exemplo n.º 2
0
    def test_compare_with_PDHG(self):
        # Load an image from the CIL gallery.
        data = dataexample.SHAPES.get()
        ig = data.geometry
        # Add gaussian noise
        noisy_data = applynoise.gaussian(data, seed=10, var=0.005)

        # TV regularisation parameter
        alpha = 1

        # fidelity = 0.5 * L2NormSquared(b=noisy_data)
        # fidelity = L1Norm(b=noisy_data)
        fidelity = KullbackLeibler(b=noisy_data, use_numba=False)

        # Setup and run the PDHG algorithm
        F = BlockFunction(alpha * MixedL21Norm(), fidelity)
        G = ZeroFunction()
        K = BlockOperator(GradientOperator(ig), IdentityOperator(ig))

        # Compute operator Norm
        normK = K.norm()

        # Primal & dual stepsizes
        sigma = 1. / normK
        tau = 1. / normK

        pdhg = PDHG(f=F,
                    g=G,
                    operator=K,
                    tau=tau,
                    sigma=sigma,
                    max_iteration=100,
                    update_objective_interval=10)
        pdhg.run(verbose=0)

        sigma = 1
        tau = sigma / normK**2

        admm = LADMM(f=G,
                     g=F,
                     operator=K,
                     tau=tau,
                     sigma=sigma,
                     max_iteration=100,
                     update_objective_interval=10)
        admm.run(verbose=0)

        from cil.utilities.quality_measures import psnr
        if debug_print:
            print("PSNR", psnr(admm.solution, pdhg.solution))
        np.testing.assert_almost_equal(psnr(admm.solution, pdhg.solution),
                                       84.46678222768597,
                                       decimal=4)
    def test_PDHG_strongly_convex_both_fconj_and_g(self):

        ig = ImageGeometry(3,3)
        data = ig.allocate('random')

        f = L2NormSquared(b=data)
        g = L2NormSquared()
        operator = IdentityOperator(ig)
    
        try:
            pdhg = PDHG(f=f, g=g, operator=operator, max_iteration=10, 
                        gamma_g = 0.5, gamma_fconj=0.5)
            pdhg.run(verbose=0)
        except ValueError as err:
            print(err)
Exemplo n.º 4
0
 def test_exception_initial_PDHG(self):
     initial = 1
     try:
         algo = PDHG(initial=initial, x_init=initial)
         assert False
     except ValueError as ve:
         assert True
 def test_exception_initial_PDHG(self):
     initial = 1
     try:
         algo = PDHG(initial = initial, x_init=initial, f=None, g=None, operator=None)
         assert False
     except ValueError as ve:
         assert True
    def test_PDHG_strongly_convex_gamma_fcong(self):

        ig = ImageGeometry(3,3)
        data = ig.allocate('random')

        f = L2NormSquared(b=data)
        g = L2NormSquared()
        operator = IdentityOperator(ig)

        # sigma, tau 
        sigma = 1.0
        tau  = 1.0        

        pdhg = PDHG(f=f, g=g, operator=operator, sigma = sigma, tau=tau,
                    max_iteration=5, gamma_fconj=0.5)
        pdhg.run(1, verbose=0)
        self.assertEquals(pdhg.theta, 1.0/ np.sqrt(1 + 2 * pdhg.gamma_fconj * sigma))
        self.assertEquals(pdhg.tau, tau / pdhg.theta)
        self.assertEquals(pdhg.sigma, sigma * pdhg.theta)
        pdhg.run(4, verbose=0)
        self.assertNotEqual(pdhg.sigma, sigma)
        self.assertNotEqual(pdhg.tau, tau) 

        # check negative strongly convex constant
        try:
            pdhg = PDHG(f=f, g=g, operator=operator, sigma = sigma, tau=tau,
                max_iteration=5, gamma_fconj=-0.5) 
        except ValueError as ve:
            print(ve) 

        # check strongly convex constant not a number
        try:
            pdhg = PDHG(f=f, g=g, operator=operator, sigma = sigma, tau=tau,
                max_iteration=5, gamma_fconj="-0.5") 
        except ValueError as ve:
            print(ve)                         
Exemplo n.º 7
0
    def test_PDHG_Denoising(self):
        print("PDHG Denoising with 3 noises")
        # adapted from demo PDHG_TV_Color_Denoising.py in CIL-Demos repository

        data = dataexample.PEPPERS.get(size=(256, 256))
        ig = data.geometry
        ag = ig

        which_noise = 0
        # Create noisy data.
        noises = ['gaussian', 'poisson', 's&p']
        dnoise = noises[which_noise]

        def setup(data, dnoise):
            if dnoise == 's&p':
                n1 = applynoise.saltnpepper(data,
                                            salt_vs_pepper=0.9,
                                            amount=0.2,
                                            seed=10)
            elif dnoise == 'poisson':
                scale = 5
                n1 = applynoise.poisson(data.as_array() / scale,
                                        seed=10) * scale
            elif dnoise == 'gaussian':
                n1 = applynoise.gaussian(data.as_array(), seed=10)
            else:
                raise ValueError('Unsupported Noise ', noise)
            noisy_data = ig.allocate()
            noisy_data.fill(n1)

            # Regularisation Parameter depending on the noise distribution
            if dnoise == 's&p':
                alpha = 0.8
            elif dnoise == 'poisson':
                alpha = 1
            elif dnoise == 'gaussian':
                alpha = .3
                # fidelity
            if dnoise == 's&p':
                g = L1Norm(b=noisy_data)
            elif dnoise == 'poisson':
                g = KullbackLeibler(b=noisy_data)
            elif dnoise == 'gaussian':
                g = 0.5 * L2NormSquared(b=noisy_data)
            return noisy_data, alpha, g

        noisy_data, alpha, g = setup(data, dnoise)
        operator = GradientOperator(
            ig, correlation=GradientOperator.CORRELATION_SPACE)

        f1 = alpha * MixedL21Norm()

        # Compute operator Norm
        normK = operator.norm()

        # Primal & dual stepsizes
        sigma = 1
        tau = 1 / (sigma * normK**2)

        # Setup and run the PDHG algorithm
        pdhg1 = PDHG(f=f1, g=g, operator=operator, tau=tau, sigma=sigma)
        pdhg1.max_iteration = 2000
        pdhg1.update_objective_interval = 200
        pdhg1.run(1000, verbose=0)

        rmse = (pdhg1.get_output() - data).norm() / data.as_array().size
        if debug_print:
            print("RMSE", rmse)
        self.assertLess(rmse, 2e-4)

        which_noise = 1
        noise = noises[which_noise]
        noisy_data, alpha, g = setup(data, noise)
        operator = GradientOperator(
            ig, correlation=GradientOperator.CORRELATION_SPACE)

        f1 = alpha * MixedL21Norm()

        # Compute operator Norm
        normK = operator.norm()

        # Primal & dual stepsizes
        sigma = 1
        tau = 1 / (sigma * normK**2)

        # Setup and run the PDHG algorithm
        pdhg1 = PDHG(f=f1,
                     g=g,
                     operator=operator,
                     tau=tau,
                     sigma=sigma,
                     max_iteration=2000,
                     update_objective_interval=200)

        pdhg1.run(1000, verbose=0)

        rmse = (pdhg1.get_output() - data).norm() / data.as_array().size
        if debug_print:
            print("RMSE", rmse)
        self.assertLess(rmse, 2e-4)

        which_noise = 2
        noise = noises[which_noise]
        noisy_data, alpha, g = setup(data, noise)
        operator = GradientOperator(
            ig, correlation=GradientOperator.CORRELATION_SPACE)

        f1 = alpha * MixedL21Norm()

        # Compute operator Norm
        normK = operator.norm()

        # Primal & dual stepsizes
        sigma = 1
        tau = 1 / (sigma * normK**2)

        # Setup and run the PDHG algorithm
        pdhg1 = PDHG(f=f1, g=g, operator=operator, tau=tau, sigma=sigma)
        pdhg1.max_iteration = 2000
        pdhg1.update_objective_interval = 200
        pdhg1.run(1000, verbose=0)

        rmse = (pdhg1.get_output() - data).norm() / data.as_array().size
        if debug_print:
            print("RMSE", rmse)
        self.assertLess(rmse, 2e-4)
Exemplo n.º 8
0
    def test_PDHG_vs_PDHG_explicit_axpby(self):
        data = dataexample.SIMPLE_PHANTOM_2D.get(size=(128, 128))
        if debug_print:
            print("test_PDHG_vs_PDHG_explicit_axpby here")
        ig = data.geometry
        ig.voxel_size_x = 0.1
        ig.voxel_size_y = 0.1

        detectors = ig.shape[0]
        angles = np.linspace(0, np.pi, 180)
        ag = AcquisitionGeometry('parallel',
                                 '2D',
                                 angles,
                                 detectors,
                                 pixel_size_h=0.1,
                                 angle_unit='radian')

        dev = 'cpu'

        Aop = AstraProjectorSimple(ig, ag, dev)

        sin = Aop.direct(data)
        # Create noisy data. Apply Gaussian noise
        noises = ['gaussian', 'poisson']
        noise = noises[1]
        if noise == 'poisson':
            np.random.seed(10)
            scale = 5
            eta = 0
            noisy_data = AcquisitionData(
                np.random.poisson(scale * (eta + sin.as_array())) / scale,
                geometry=ag)
        elif noise == 'gaussian':
            np.random.seed(10)
            n1 = np.random.normal(0, 0.1, size=ag.shape)
            noisy_data = AcquisitionData(n1 + sin.as_array(), geometry=ag)

        else:
            raise ValueError('Unsupported Noise ', noise)

        alpha = 0.5
        op1 = GradientOperator(ig)
        op2 = Aop
        # Create BlockOperator
        operator = BlockOperator(op1, op2, shape=(2, 1))
        f2 = KullbackLeibler(b=noisy_data)
        g = IndicatorBox(lower=0)
        normK = operator.norm()
        sigma = 1. / normK
        tau = 1. / normK

        f1 = alpha * MixedL21Norm()
        f = BlockFunction(f1, f2)
        # Setup and run the PDHG algorithm

        algos = []
        algos.append(
            PDHG(f=f,
                 g=g,
                 operator=operator,
                 tau=tau,
                 sigma=sigma,
                 max_iteration=1000,
                 update_objective_interval=200,
                 use_axpby=True))
        algos[0].run(1000, verbose=0)

        algos.append(
            PDHG(f=f,
                 g=g,
                 operator=operator,
                 tau=tau,
                 sigma=sigma,
                 max_iteration=1000,
                 update_objective_interval=200,
                 use_axpby=False))
        algos[1].run(1000, verbose=0)

        from cil.utilities.quality_measures import mae, mse, psnr
        qm = (mae(algos[0].get_output(), algos[1].get_output()),
              mse(algos[0].get_output(), algos[1].get_output()),
              psnr(algos[0].get_output(), algos[1].get_output()))
        if debug_print:
            print("Quality measures", qm)
        np.testing.assert_array_less(qm[0], 0.005)
        np.testing.assert_array_less(qm[1], 3e-05)
Exemplo n.º 9
0
 # Create BlockOperator
 operator = BlockOperator(op1, op2, shape=(2,1) ) 
 
 # Create functions      
 f = BlockFunction(f1, f2) 
 g = ZeroFunction()
         
 # Compute operator Norm
 normK = operator.norm()
 
 # Primal & dual stepsizes
 sigma = 1
 tau = 1/(sigma*normK**2)
 
 # Setup and run the PDHG algorithm
 pdhg = PDHG(f=f,g=g,operator=operator, tau=tau, sigma=sigma)
 pdhg.max_iteration = 10000
 pdhg.update_objective_interval = 1
 pdhg.run(200,very_verbose=True)
 
 # Show results
 plt.figure(figsize=(20,5))
 plt.subplot(1,3,1)
 plt.imshow(data_gray.as_array(),vmin=0.0,vmax=1.0)
 plt.title('Ground Truth')
 plt.gray()
 plt.colorbar()
 plt.subplot(1,3,2)
 plt.imshow(blurredimage.as_array(),vmin=0.0,vmax=1.0)
 plt.title('Noisy and Masked Data')
 plt.gray()
Exemplo n.º 10
0
    cProfile.run('algo.run(1)')

    # %%
    from cil.optimisation.algorithms import PDHG
    from cil.optimisation.functions import MixedL21Norm, BlockFunction, L2NormSquared, IndicatorBox
    from cil.optimisation.operators import GradientOperator, BlockOperator

    nabla = GradientOperator(ig_cs, backend='c')
    F = BlockFunction(L2NormSquared(b=ldata), alpha * MixedL21Norm())
    BK = BlockOperator(K, nabla)
    # normK = BK.norm()
    normK = 191.54791313753265

    pdhg = PDHG(f=F,
                g=IndicatorBox(lower=0.),
                operator=BK,
                max_iteration=1000,
                update_objective_interval=100)
    #%%
    pdhg.run(100, verbose=2, print_interval=10)
    #%%
    plotter2D(pdhg.solution, cmap='gist_earth')

    # %%

    subsets = AcquisitionGeometrySubsetGenerator.generate_subset(
        ag_shift, num_subsets=8, method='stagger')
    print(subsets[0])
    #%%
    from cil.optimisation.algorithms import SPDHG
    from cil.optimisation.functions import ZeroFunction
    def test_PDHG_step_sizes(self):

        ig = ImageGeometry(3,3)
        data = ig.allocate('random')

        f = L2NormSquared(b=data)
        g = L2NormSquared()
        operator = 3*IdentityOperator(ig)

        #check if sigma, tau are None 
        pdhg = PDHG(f=f, g=g, operator=operator, max_iteration=10)
        self.assertAlmostEqual(pdhg.sigma, 1./operator.norm())
        self.assertAlmostEqual(pdhg.tau, 1./operator.norm())

        #check if sigma is negative
        with self.assertRaises(ValueError):
            pdhg = PDHG(f=f, g=g, operator=operator, max_iteration=10, sigma = -1)
        
        #check if tau is negative
        with self.assertRaises(ValueError):
            pdhg = PDHG(f=f, g=g, operator=operator, max_iteration=10, tau = -1)
        
        #check if tau is None 
        sigma = 3.0
        pdhg = PDHG(f=f, g=g, operator=operator, sigma = sigma, max_iteration=10)
        self.assertAlmostEqual(pdhg.sigma, sigma)
        self.assertAlmostEqual(pdhg.tau, 1./(sigma * operator.norm()**2)) 

        #check if sigma is None 
        tau = 3.0
        pdhg = PDHG(f=f, g=g, operator=operator, tau = tau, max_iteration=10)
        self.assertAlmostEqual(pdhg.tau, tau)
        self.assertAlmostEqual(pdhg.sigma, 1./(tau * operator.norm()**2)) 

        #check if sigma/tau are not None 
        tau = 1.0
        sigma = 1.0
        pdhg = PDHG(f=f, g=g, operator=operator, tau = tau, sigma = sigma, max_iteration=10)
        self.assertAlmostEqual(pdhg.tau, tau)
        self.assertAlmostEqual(pdhg.sigma, sigma) 

        #check sigma/tau as arrays, sigma wrong shape
        ig1 = ImageGeometry(2,2)
        sigma = ig1.allocate()
        with self.assertRaises(ValueError):
            pdhg = PDHG(f=f, g=g, operator=operator, sigma = sigma, max_iteration=10)

        #check sigma/tau as arrays, tau wrong shape
        tau = ig1.allocate()
        with self.assertRaises(ValueError):
            pdhg = PDHG(f=f, g=g, operator=operator, tau = tau, max_iteration=10)
        
        # check sigma not Number or object with correct shape
        with self.assertRaises(AttributeError):
            pdhg = PDHG(f=f, g=g, operator=operator, sigma = "sigma", max_iteration=10)
        
        # check tau not Number or object with correct shape
        with self.assertRaises(AttributeError):
            pdhg = PDHG(f=f, g=g, operator=operator, tau = "tau", max_iteration=10)
        
        # check warning message if condition is not satisfied
        sigma = 4
        tau = 1/3
        with warnings.catch_warnings(record=True) as wa:
            pdhg = PDHG(f=f, g=g, operator=operator, tau = tau, sigma = sigma, max_iteration=10)  
            assert "Convergence criterion" in str(wa[0].message)             
Exemplo n.º 12
0
    # Create BlockOperator
    operator = BlockOperator(op1, op2, shape=(2, 1))

    # Create functions
    f = BlockFunction(alpha * MixedL21Norm(), f2)
    g = ZeroFunction()

    # Compute operator Norm
    normK = operator.norm()

    # Primal & dual stepsizes
    sigma = 1
    tau = 1 / (sigma * normK**2)

    # Setup and run the PDHG algorithm
    pdhg = PDHG(f=f, g=g, operator=operator, tau=tau, sigma=sigma)
    pdhg.max_iteration = 2000
    pdhg.update_objective_interval = 100
    pdhg.run(2000)

    # Show results
    plt.figure(figsize=(20, 5))
    plt.subplot(1, 4, 1)
    plt.imshow(data.as_array())
    plt.title('Ground Truth')
    plt.colorbar()
    plt.subplot(1, 4, 2)
    plt.imshow(noisy_data.as_array())
    plt.title('Noisy Data')
    plt.colorbar()
    plt.subplot(1, 4, 3)
Exemplo n.º 13
0
    def single_sino(sino: np.ndarray,
                    cor: ScalarCoR,
                    proj_angles: ProjectionAngles,
                    recon_params: ReconstructionParameters,
                    progress: Optional[Progress] = None):
        """
        Reconstruct a single slice from a single sinogram. Used for the preview and the single slice button.
        Should return a numpy array,
        """

        if progress:
            progress.add_estimated_steps(recon_params.num_iter + 1)
            progress.update(steps=1,
                            msg='CIL: Setting up reconstruction',
                            force_continue=False)

        if cil_mutex.locked():
            LOG.warning("CIL recon already in progress")

        with cil_mutex:
            sino = BaseRecon.prepare_sinogram(sino, recon_params)
            pixel_num_h = sino.shape[1]
            pixel_size = 1.
            rot_pos_x = (cor.value - pixel_num_h / 2) * pixel_size
            ag = AcquisitionGeometry.create_Parallel2D(
                rotation_axis_position=[rot_pos_x, 0])

            ag.set_panel(pixel_num_h, pixel_size=pixel_size)
            ag.set_labels(DataOrder.ASTRA_AG_LABELS)
            ag.set_angles(angles=proj_angles.value, angle_unit='radian')

            # stick it into an AcquisitionData
            data = ag.allocate(None)
            data.fill(sino)

            alpha = recon_params.alpha

            ig = ag.get_ImageGeometry()
            # set up TV regularisation
            K, f1, f2, G = CILRecon.set_up_TV_regularisation(ig, data, alpha)

            # alpha = 1.0
            # f1 =  alpha * MixedL21Norm()
            # f2 = 0.5 * L2NormSquared(b=ad2d)

            F = BlockFunction(f1, f2)
            normK = K.norm()
            sigma = 1
            tau = 1 / (sigma * normK**2)

            pdhg = PDHG(f=F,
                        g=G,
                        operator=K,
                        tau=tau,
                        sigma=sigma,
                        max_iteration=100000,
                        update_objective_interval=10)

            try:
                for iter in range(recon_params.num_iter):
                    if progress:
                        progress.update(
                            steps=1,
                            msg=
                            f'CIL: Iteration {iter + 1} of {recon_params.num_iter}'
                            f': Objective {pdhg.get_last_objective():.2f}',
                            force_continue=False)
                    pdhg.next()
            finally:
                if progress:
                    progress.mark_complete()
            return pdhg.solution.as_array()
Exemplo n.º 14
0
    def full(images: Images,
             cors: List[ScalarCoR],
             recon_params: ReconstructionParameters,
             progress: Optional[Progress] = None):
        """
        Performs a volume reconstruction using sample data provided as sinograms.

        :param images: Array of sinogram images
        :param cors: Array of centre of rotation values
        :param proj_angles: Array of projection angles in radians
        :param recon_params: Reconstruction Parameters
        :param progress: Optional progress reporter
        :return: 3D image data for reconstructed volume
        """

        progress = Progress.ensure_instance(progress,
                                            task_name='CIL reconstruction',
                                            num_steps=recon_params.num_iter +
                                            1)

        projection_size = full_size_KB(images.data.shape, images.dtype)
        recon_volume_shape = images.data.shape[2], images.data.shape[
            2], images.data.shape[1]
        recon_volume_size = full_size_KB(recon_volume_shape, images.dtype)
        estimated_mem_required = 5 * projection_size + 13 * recon_volume_size
        free_mem = system_free_memory().kb()

        if (estimated_mem_required > free_mem):
            estimate_gb = estimated_mem_required / 1024 / 1024
            raise RuntimeError(
                "The machine does not have enough physical memory available to allocate space for this data."
                f" Estimated RAM needed is {estimate_gb:.2f} GB")

        if cil_mutex.locked():
            LOG.warning("CIL recon already in progress")

        with cil_mutex:
            progress.update(steps=1,
                            msg='CIL: Setting up reconstruction',
                            force_continue=False)
            angles = images.projection_angles(
                recon_params.max_projection_angle).value
            shape = images.data.shape
            pixel_num_h, pixel_num_v = shape[2], shape[1]
            pixel_size = 1.
            if recon_params.tilt is None:
                raise ValueError("recon_params.tilt is not set")
            rot_pos = [
                (cors[pixel_num_v // 2].value - pixel_num_h / 2) * pixel_size,
                0, 0
            ]
            slope = -np.tan(np.deg2rad(recon_params.tilt.value))
            rot_angle = [slope, 0, 1]

            ag = AcquisitionGeometry.create_Parallel3D(
                rotation_axis_position=rot_pos,
                rotation_axis_direction=rot_angle)
            ag.set_panel([pixel_num_h, pixel_num_v],
                         pixel_size=(pixel_size, pixel_size))
            ag.set_angles(angles=angles, angle_unit='radian')
            ag.set_labels(DataOrder.TIGRE_AG_LABELS)

            # stick it into an AcquisitionData
            data = ag.allocate(None)
            data.fill(BaseRecon.prepare_sinogram(images.data, recon_params))
            data.reorder('astra')

            alpha = recon_params.alpha

            ig = ag.get_ImageGeometry()
            # set up TV regularisation
            K, f1, f2, G = CILRecon.set_up_TV_regularisation(ig, data, alpha)

            # alpha = 1.0
            # f1 =  alpha * MixedL21Norm()
            # f2 = 0.5 * L2NormSquared(b=ad2d)
            F = BlockFunction(f1, f2)
            normK = K.norm()
            sigma = 1
            tau = 1 / (sigma * normK**2)

            pdhg = PDHG(f=F,
                        g=G,
                        operator=K,
                        tau=tau,
                        sigma=sigma,
                        max_iteration=100000,
                        update_objective_interval=10)

            with progress:
                for iter in range(recon_params.num_iter):
                    progress.update(
                        steps=1,
                        msg=
                        f'CIL: Iteration {iter+1} of {recon_params.num_iter}:'
                        f'Objective {pdhg.get_last_objective():.2f}',
                        force_continue=False)
                    pdhg.next()
                volume = pdhg.solution.as_array()
                LOG.info('Reconstructed 3D volume with shape: {0}'.format(
                    volume.shape))
            return Images(volume)
Exemplo n.º 15
0
    # Create BlockOperator
    operator = BlockOperator(op1, op2, shape=(2,1) ) 

    # Create functions      
    f = BlockFunction(alpha * MixedL21Norm(), f2) 
    g = ZeroFunction()
            
    # Compute operator Norm
    normK = operator.norm()
    
    # Primal & dual stepsizes
    sigma = 1
    tau = 1/(sigma*normK**2)
    
    # Setup and run the PDHG algorithm
    pdhg = PDHG(f=f,g=g,operator=operator, tau=tau, sigma=sigma)
    pdhg.max_iteration = 2000
    pdhg.update_objective_interval = 100
    pdhg.run(2000)
    
    # Show results
    plt.figure(figsize=(20,5))
    plt.subplot(1,4,1)
    plt.imshow(data.as_array())
    plt.title('Ground Truth')
    plt.colorbar()
    plt.subplot(1,4,2)
    plt.imshow(noisy_data.as_array())
    plt.title('Noisy Data')
    plt.colorbar()
    plt.subplot(1,4,3)
Exemplo n.º 16
0
    def test_SPDHG_vs_PDHG_implicit(self):

        data = dataexample.SIMPLE_PHANTOM_2D.get(size=(128, 128))

        ig = data.geometry
        ig.voxel_size_x = 0.1
        ig.voxel_size_y = 0.1

        detectors = ig.shape[0]
        angles = np.linspace(0, np.pi, 90)
        ag = AcquisitionGeometry('parallel',
                                 '2D',
                                 angles,
                                 detectors,
                                 pixel_size_h=0.1,
                                 angle_unit='radian')
        # Select device
        dev = 'cpu'

        Aop = AstraProjectorSimple(ig, ag, dev)

        sin = Aop.direct(data)
        # Create noisy data. Apply Gaussian noise
        noises = ['gaussian', 'poisson']
        noise = noises[1]
        noisy_data = ag.allocate()
        if noise == 'poisson':
            np.random.seed(10)
            scale = 20
            eta = 0
            noisy_data.fill(
                np.random.poisson(scale * (eta + sin.as_array())) / scale)
        elif noise == 'gaussian':
            np.random.seed(10)
            n1 = np.random.normal(0, 0.1, size=ag.shape)
            noisy_data.fill(n1 + sin.as_array())

        else:
            raise ValueError('Unsupported Noise ', noise)

        # Create BlockOperator
        operator = Aop
        f = KullbackLeibler(b=noisy_data)
        alpha = 0.005
        g = alpha * TotalVariation(50, 1e-4, lower=0)
        normK = operator.norm()

        #% 'implicit' PDHG, preconditioned step-sizes
        tau_tmp = 1.
        sigma_tmp = 1.
        tau = sigma_tmp / operator.adjoint(
            tau_tmp * operator.range_geometry().allocate(1.))
        sigma = tau_tmp / operator.direct(
            sigma_tmp * operator.domain_geometry().allocate(1.))
        #    initial = operator.domain_geometry().allocate()

        #    # Setup and run the PDHG algorithm
        pdhg = PDHG(f=f,
                    g=g,
                    operator=operator,
                    tau=tau,
                    sigma=sigma,
                    max_iteration=1000,
                    update_objective_interval=500)
        pdhg.run(verbose=0)

        subsets = 10
        size_of_subsets = int(len(angles) / subsets)
        # take angles and create uniform subsets in uniform+sequential setting
        list_angles = [
            angles[i:i + size_of_subsets]
            for i in range(0, len(angles), size_of_subsets)
        ]
        # create acquisitioin geometries for each the interval of splitting angles
        list_geoms = [
            AcquisitionGeometry('parallel',
                                '2D',
                                list_angles[i],
                                detectors,
                                pixel_size_h=0.1,
                                angle_unit='radian')
            for i in range(len(list_angles))
        ]
        # create with operators as many as the subsets
        A = BlockOperator(*[
            AstraProjectorSimple(ig, list_geoms[i], dev)
            for i in range(subsets)
        ])
        ## number of subsets
        #(sub2ind, ind2sub) = divide_1Darray_equally(range(len(A)), subsets)
        #
        ## acquisisiton data
        AD_list = []
        for sub_num in range(subsets):
            for i in range(0, len(angles), size_of_subsets):
                arr = noisy_data.as_array()[i:i + size_of_subsets, :]
                AD_list.append(
                    AcquisitionData(arr, geometry=list_geoms[sub_num]))

        g = BlockDataContainer(*AD_list)

        ## block function
        F = BlockFunction(*[KullbackLeibler(b=g[i]) for i in range(subsets)])
        G = alpha * TotalVariation(50, 1e-4, lower=0)

        prob = [1 / len(A)] * len(A)
        spdhg = SPDHG(f=F,
                      g=G,
                      operator=A,
                      max_iteration=1000,
                      update_objective_interval=200,
                      prob=prob)
        spdhg.run(1000, verbose=0)
        from cil.utilities.quality_measures import mae, mse, psnr
        qm = (mae(spdhg.get_output(),
                  pdhg.get_output()), mse(spdhg.get_output(),
                                          pdhg.get_output()),
              psnr(spdhg.get_output(), pdhg.get_output()))
        if debug_print:
            print("Quality measures", qm)

        np.testing.assert_almost_equal(mae(spdhg.get_output(),
                                           pdhg.get_output()),
                                       0.000335,
                                       decimal=3)
        np.testing.assert_almost_equal(mse(spdhg.get_output(),
                                           pdhg.get_output()),
                                       5.51141e-06,
                                       decimal=3)
Exemplo n.º 17
0
    def test_SPDHG_vs_PDHG_explicit(self):
        data = dataexample.SIMPLE_PHANTOM_2D.get(size=(128, 128))

        ig = data.geometry
        ig.voxel_size_x = 0.1
        ig.voxel_size_y = 0.1

        detectors = ig.shape[0]
        angles = np.linspace(0, np.pi, 180)
        ag = AcquisitionGeometry('parallel',
                                 '2D',
                                 angles,
                                 detectors,
                                 pixel_size_h=0.1,
                                 angle_unit='radian')
        # Select device
        dev = 'cpu'

        Aop = AstraProjectorSimple(ig, ag, dev)

        sin = Aop.direct(data)
        # Create noisy data. Apply Gaussian noise
        noises = ['gaussian', 'poisson']
        noise = noises[1]
        if noise == 'poisson':
            scale = 5
            noisy_data = scale * applynoise.poisson(sin / scale, seed=10)
            # np.random.seed(10)
            # scale = 5
            # eta = 0
            # noisy_data = AcquisitionData(np.random.poisson( scale * (eta + sin.as_array()))/scale, ag)
        elif noise == 'gaussian':
            noisy_data = noise.gaussian(sin, var=0.1, seed=10)
            # np.random.seed(10)
            # n1 = np.random.normal(0, 0.1, size = ag.shape)
            # noisy_data = AcquisitionData(n1 + sin.as_array(), ag)

        else:
            raise ValueError('Unsupported Noise ', noise)

        #%% 'explicit' SPDHG, scalar step-sizes
        subsets = 10
        size_of_subsets = int(len(angles) / subsets)
        # create Gradient operator
        op1 = GradientOperator(ig)
        # take angles and create uniform subsets in uniform+sequential setting
        list_angles = [
            angles[i:i + size_of_subsets]
            for i in range(0, len(angles), size_of_subsets)
        ]
        # create acquisitioin geometries for each the interval of splitting angles
        list_geoms = [
            AcquisitionGeometry('parallel',
                                '2D',
                                list_angles[i],
                                detectors,
                                pixel_size_h=0.1,
                                angle_unit='radian')
            for i in range(len(list_angles))
        ]
        # create with operators as many as the subsets
        A = BlockOperator(*[
            AstraProjectorSimple(ig, list_geoms[i], dev)
            for i in range(subsets)
        ] + [op1])
        ## number of subsets
        #(sub2ind, ind2sub) = divide_1Darray_equally(range(len(A)), subsets)
        #
        ## acquisisiton data
        ## acquisisiton data
        AD_list = []
        for sub_num in range(subsets):
            for i in range(0, len(angles), size_of_subsets):
                arr = noisy_data.as_array()[i:i + size_of_subsets, :]
                AD_list.append(
                    AcquisitionData(arr, geometry=list_geoms[sub_num]))

        g = BlockDataContainer(*AD_list)
        alpha = 0.5
        ## block function
        F = BlockFunction(*[
            *[KullbackLeibler(b=g[i])
              for i in range(subsets)] + [alpha * MixedL21Norm()]
        ])
        G = IndicatorBox(lower=0)

        prob = [1 / (2 * subsets)] * (len(A) - 1) + [1 / 2]
        spdhg = SPDHG(f=F,
                      g=G,
                      operator=A,
                      max_iteration=1000,
                      update_objective_interval=200,
                      prob=prob)
        spdhg.run(1000, verbose=0)

        #%% 'explicit' PDHG, scalar step-sizes
        op1 = GradientOperator(ig)
        op2 = Aop
        # Create BlockOperator
        operator = BlockOperator(op1, op2, shape=(2, 1))
        f2 = KullbackLeibler(b=noisy_data)
        g = IndicatorBox(lower=0)
        normK = operator.norm()
        sigma = 1 / normK
        tau = 1 / normK

        f1 = alpha * MixedL21Norm()
        f = BlockFunction(f1, f2)
        # Setup and run the PDHG algorithm
        pdhg = PDHG(f=f, g=g, operator=operator, tau=tau, sigma=sigma)
        pdhg.max_iteration = 1000
        pdhg.update_objective_interval = 200
        pdhg.run(1000, verbose=0)

        #%% show diff between PDHG and SPDHG
        # plt.imshow(spdhg.get_output().as_array() -pdhg.get_output().as_array())
        # plt.colorbar()
        # plt.show()

        from cil.utilities.quality_measures import mae, mse, psnr
        qm = (mae(spdhg.get_output(),
                  pdhg.get_output()), mse(spdhg.get_output(),
                                          pdhg.get_output()),
              psnr(spdhg.get_output(), pdhg.get_output()))
        if debug_print:
            print("Quality measures", qm)
        np.testing.assert_almost_equal(mae(spdhg.get_output(),
                                           pdhg.get_output()),
                                       0.00150,
                                       decimal=3)
        np.testing.assert_almost_equal(mse(spdhg.get_output(),
                                           pdhg.get_output()),
                                       1.68590e-05,
                                       decimal=3)
Exemplo n.º 18
0
plotter2D(algo.solution, cmap='gist_earth')

# %%
from cil.optimisation.algorithms import PDHG
from cil.optimisation.functions import MixedL21Norm, BlockFunction, L2NormSquared, IndicatorBox
from cil.optimisation.operators import GradientOperator, BlockOperator

nabla = GradientOperator(ig_cs, backend='c')
F = BlockFunction(0.5 * L2NormSquared(b=ldata), alpha * MixedL21Norm())
BK = BlockOperator(K, nabla)
normK = BK.norm()

pdhg = PDHG(f=F,
            g=IndicatorBox(lower=0.),
            operator=BK,
            max_iteration=1000,
            update_objective_interval=100)
#%%
# pdhg.run(1000, verbose=2)
#%%
plotter2D(pdhg.solution, cmap='gist_earth')

# %%


class AcquisitionGeometrySubsetGenerator(object):
    '''AcquisitionGeometrySubsetGenerator is a factory that helps generating subsets of AcquisitionData
    
    AcquisitionGeometrySubsetGenerator generates the indices to slice the data array in AcquisitionData along the 
    angle dimension with 4 methods: