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")
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_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)
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)
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)
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)
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)
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)
# 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()
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)
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()
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)
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