def create_simple_ImageData(self): N = 64 ig = ImageGeometry(voxel_num_x=N, voxel_num_y=N) Phantom = ImageData(geometry=ig) x = Phantom.as_array() x[int(round(N/4)):int(round(3*N/4)), int(round(N/4)):int(round(3*N/4))] = 0.5 x[int(round(N/8)):int(round(7*N/8)), int(round(3*N/8)):int(round(5*N/8))] = 1 return (ig, Phantom)
def test_BlockDataContainer_fill(self): print("test block data container") ig0 = ImageGeometry(2, 3, 4) ig1 = ImageGeometry(2, 3, 5) data0 = ImageData(geometry=ig0) data1 = ImageData(geometry=ig1) + 1 data2 = ImageData(geometry=ig0) + 2 data3 = ImageData(geometry=ig1) + 3 cp0 = BlockDataContainer(data0, data1) #cp1 = BlockDataContainer(data2,data3) cp2 = BlockDataContainer(data0 + 1, data1 + 1) data0.fill(data2) self.assertNumpyArrayEqual(data0.as_array(), data2.as_array()) data0 = ImageData(geometry=ig0) for el, ot in zip(cp0, cp2): print(el.shape, ot.shape) cp0.fill(cp2) self.assertBlockDataContainerEqual(cp0, cp2)
def process(self): DATA = self.get_input() IM = ImageData(geometry=self.volume_geometry) for k in range(IM.geometry.channels): rec_id, IM.as_array()[k] = astra.create_backprojection( DATA.as_array()[k], self.proj_id) astra.data2d.delete(rec_id) if self.device == 'cpu': return IM else: scaling = self.volume_geometry.voxel_size_x**3 return scaling * IM
def setupCCPiGeometries(voxel_num_x, voxel_num_y, voxel_num_z, angles, counter): vg = ImageGeometry(voxel_num_x=voxel_num_x,voxel_num_y=voxel_num_y, voxel_num_z=voxel_num_z) Phantom_ccpi = ImageData(geometry=vg, dimension_labels=['horizontal_x','horizontal_y','vertical']) #.subset(['horizontal_x','horizontal_y','vertical']) # ask the ccpi code what dimensions it would like voxel_per_pixel = 1 geoms = pbalg.pb_setup_geometry_from_image(Phantom_ccpi.as_array(), angles, voxel_per_pixel ) pg = AcquisitionGeometry('parallel', '3D', angles, geoms['n_h'], 1.0, geoms['n_v'], 1.0 #2D in 3D is a slice 1 pixel thick ) center_of_rotation = Phantom_ccpi.get_dimension_size('horizontal_x') / 2 ad = AcquisitionData(geometry=pg,dimension_labels=['angle','vertical','horizontal']) geoms_i = pbalg.pb_setup_geometry_from_acquisition(ad.as_array(), angles, center_of_rotation, voxel_per_pixel ) counter+=1 if counter < 4: if (not ( geoms_i == geoms )): print ("not equal and {0}".format(counter)) X = max(geoms['output_volume_x'], geoms_i['output_volume_x']) Y = max(geoms['output_volume_y'], geoms_i['output_volume_y']) Z = max(geoms['output_volume_z'], geoms_i['output_volume_z']) return setupCCPiGeometries(X,Y,Z,angles, counter) else: return geoms else: return geoms_i
scale = 5 n1 = TestData.random_noise(data.as_array()/scale, mode = noise, seed = 10)*scale elif noise == 'gaussian': n1 = TestData.random_noise(data.as_array(), mode = noise, seed = 10) else: raise ValueError('Unsupported Noise ', noise) noisy_data = ImageData(n1) # Show Ground Truth and Noisy Data plt.figure(figsize=(10,5)) plt.subplot(1,2,1) plt.imshow(data.as_array()) plt.title('Ground Truth') plt.colorbar() plt.subplot(1,2,2) plt.imshow(noisy_data.as_array()) plt.title('Noisy Data') plt.colorbar() plt.show() # Regularisation Parameter depending on the noise distribution if noise == 's&p': alpha = 0.8 elif noise == 'poisson': alpha = .3 elif noise == 'gaussian': alpha = .2 beta = 2 * alpha # Fidelity
ims1, interval=500, blit=True, repeat_delay=10) plt.show() # Setup geometries ig = ImageGeometry(voxel_num_x=N, voxel_num_y=N, channels=np.shape(phantom_2Dt)[0]) data = ImageData(phantom_2Dt, geometry=ig) ag = ig # Create noisy data. Apply Gaussian noise np.random.seed(10) noisy_data = ImageData(data.as_array() + np.random.normal(0, 0.25, size=ig.shape)) # time-frames index tindex = [8, 16, 24] fig1, axes1 = plt.subplots(nrows=1, ncols=3, figsize=(10, 10)) plt.subplot(1, 3, 1) plt.imshow(noisy_data.as_array()[tindex[0], :, :]) plt.axis('off') plt.title('Time {}'.format(tindex[0])) plt.subplot(1, 3, 2) plt.imshow(noisy_data.as_array()[tindex[1], :, :]) plt.axis('off') plt.title('Time {}'.format(tindex[1])) plt.subplot(1, 3, 3)
if noise == 'poisson': scale = 5 eta = 0 noisy_data = AcquisitionData( np.random.poisson(scale * (eta + sin.as_array())) / scale, ag) elif noise == 'gaussian': n1 = np.random.normal(0, 1, size=ag.shape) noisy_data = AcquisitionData(n1 + sin.as_array(), ag) else: raise ValueError('Unsupported Noise ', noise) # Show Ground Truth and Noisy Data plt.figure(figsize=(10, 10)) plt.subplot(1, 2, 2) plt.imshow(data.as_array()) plt.title('Ground Truth') plt.colorbar() plt.subplot(1, 2, 1) plt.imshow(noisy_data.as_array()) plt.title('Noisy Data') plt.colorbar() plt.show() # Create operators op1 = Gradient(ig) op2 = Aop # Create BlockOperator operator = BlockOperator(op1, op2, shape=(2, 1))
test_case = 2 # Set up phantom size NxN by creating ImageGeometry, initialising the # ImageData object with this geometry and empty array and finally put some # data into its array, and display as image. N = 300 x1 = -1 x2 = 1 dx = (x2-x1)/N ig = ImageGeometry(voxel_num_x=N, voxel_num_y=N, voxel_size_x=dx, voxel_size_y=dx) Phantom = ImageData(geometry=ig) x = Phantom.as_array() x[round(N/4):round(3*N/4),round(N/4):round(3*N/4)] = 0.5 x[:,round(3*N/8):round(5*N/8)] = 1 plt.imshow(x) plt.title('Phantom image') plt.colorbar() plt.show() # Set up AcquisitionGeometry object to hold the parameters of the measurement # setup geometry: # Number of angles, the actual angles from 0 to # pi for parallel beam and 0 to 2pi for fanbeam, set the width of a detector # pixel relative to an object pixel, the number of detector pixels, and the # source-origin and origin-detector distance (here the origin-detector distance # set to 0 to simulate a "virtual detector" with same detector pixel size as # object pixel size).
def test_FISTA_denoise_cvx(self): if not cvx_not_installable: opt = {'memopt': True} N = 64 ig = ImageGeometry(voxel_num_x=N, voxel_num_y=N) Phantom = ImageData(geometry=ig) x = Phantom.as_array() x[int(round(N / 4)):int(round(3 * N / 4)), int(round(N / 4)):int(round(3 * N / 4))] = 0.5 x[int(round(N / 8)):int(round(7 * N / 8)), int(round(3 * N / 8)):int(round(5 * N / 8))] = 1 # Identity operator for denoising I = TomoIdentity(ig) # Data and add noise y = I.direct(Phantom) y.array = y.array + 0.1 * np.random.randn(N, N) # Data fidelity term f_denoise = Norm2sq(I, y, c=0.5, memopt=True) # 1-norm regulariser lam1_denoise = 1.0 g1_denoise = Norm1(lam1_denoise) # Initial guess x_init_denoise = ImageData(np.zeros((N, N))) # Combine with least squares and solve using generic FISTA implementation x_fista1_denoise, it1_denoise, timing1_denoise, \ criter1_denoise = \ FISTA(x_init_denoise, f_denoise, g1_denoise, opt=opt) print(x_fista1_denoise) print(criter1_denoise[-1]) # Now denoise LS + 1-norm with FBPD x_fbpd1_denoise, itfbpd1_denoise, timingfbpd1_denoise,\ criterfbpd1_denoise = \ FBPD(x_init_denoise, I, None, f_denoise, g1_denoise) print(x_fbpd1_denoise) print(criterfbpd1_denoise[-1]) # Compare to CVXPY # Construct the problem. x1_denoise = Variable(N**2, 1) objective1_denoise = Minimize( 0.5 * sum_squares(x1_denoise - y.array.flatten()) + lam1_denoise * norm(x1_denoise, 1)) prob1_denoise = Problem(objective1_denoise) # The optimal objective is returned by prob.solve(). result1_denoise = prob1_denoise.solve(verbose=False, solver=SCS, eps=1e-12) # The optimal solution for x is stored in x.value and optimal objective value # is in result as well as in objective.value print( "CVXPY least squares plus 1-norm solution and objective value:" ) print(x1_denoise.value) print(objective1_denoise.value) self.assertNumpyArrayAlmostEqual(x_fista1_denoise.array.flatten(), x1_denoise.value, 5) self.assertNumpyArrayAlmostEqual(x_fbpd1_denoise.array.flatten(), x1_denoise.value, 5) x1_cvx = x1_denoise.value x1_cvx.shape = (N, N) # Now TV with FBPD lam_tv = 0.1 gtv = TV2D(lam_tv) gtv(gtv.op.direct(x_init_denoise)) opt_tv = {'tol': 1e-4, 'iter': 10000} x_fbpdtv_denoise, itfbpdtv_denoise, timingfbpdtv_denoise,\ criterfbpdtv_denoise = \ FBPD(x_init_denoise, gtv.op, None, f_denoise, gtv, opt=opt_tv) print(x_fbpdtv_denoise) print(criterfbpdtv_denoise[-1]) # Compare to CVXPY # Construct the problem. xtv_denoise = Variable((N, N)) objectivetv_denoise = Minimize(0.5 * sum_squares(xtv_denoise - y.array) + lam_tv * tv(xtv_denoise)) probtv_denoise = Problem(objectivetv_denoise) # The optimal objective is returned by prob.solve(). resulttv_denoise = probtv_denoise.solve(verbose=False, solver=SCS, eps=1e-12) # The optimal solution for x is stored in x.value and optimal objective value # is in result as well as in objective.value print( "CVXPY least squares plus 1-norm solution and objective value:" ) print(xtv_denoise.value) print(objectivetv_denoise.value) self.assertNumpyArrayAlmostEqual(x_fbpdtv_denoise.as_array(), xtv_denoise.value, 1) else: self.assertTrue(cvx_not_installable)
ag = ig N = 300 # Create Noisy data with Poisson noise scale = 5 n1 = TestData.random_noise(data.as_array() / scale, mode='poisson', seed=10) * scale noisy_data = ImageData(n1) # Show Ground Truth and Noisy Data plt.figure(figsize=(10, 10)) plt.subplot(2, 1, 1) plt.imshow(data.as_array()) plt.title('Ground Truth') plt.colorbar() plt.subplot(2, 1, 2) plt.imshow(noisy_data.as_array()) plt.title('Noisy Data') plt.colorbar() plt.show() # Regularisation Parameter alpha = 10 # Setup and run the FISTA algorithm operator = Gradient(ig) fid = KullbackLeibler(noisy_data) def KL_Prox_PosCone(x, tau, out=None): if out is None:
data = ImageData(phantom_2D) detectors = N angles = np.linspace(0, np.pi, 128, dtype=np.float32) ag = AcquisitionGeometry('parallel', '2D', angles, detectors) Aop = AstraProjectorSimple(ig, ag, dev) sin = Aop.direct(data) #noisy_data = AcquisitionData( sin.as_array() + np.random.normal(0,1,ag.shape)) noisy_data = AcquisitionData(sin.as_array()) # Show Ground Truth and Noisy Data plt.figure(figsize=(10, 10)) plt.subplot(2, 1, 1) plt.imshow(data.as_array()) plt.title('Ground Truth') plt.colorbar() plt.subplot(2, 1, 2) plt.imshow(noisy_data.as_array()) plt.title('Noisy Data') plt.colorbar() plt.show() # Setup and run the CGLS algorithm alpha = 2 Grad = Gradient(ig) Id = Identity(ig) # Form Tikhonov as a Block CGLS structure op_CGLS = BlockOperator(Aop, alpha * Grad, shape=(2, 1))
if noise == 'poisson': scale = 5 eta = 0 noisy_data = AcquisitionData( np.random.poisson(scale * (eta + sin.as_array())) / scale, ag) elif noise == 'gaussian': n1 = np.random.normal(0, 1, size=ag.shape) noisy_data = AcquisitionData(n1 + sin.as_array(), ag) else: raise ValueError('Unsupported Noise ', noise) # Show Ground Truth and Noisy Data plt.figure(figsize=(10, 10)) plt.subplot(1, 2, 2) plt.imshow(data.as_array()) plt.title('Ground Truth') plt.colorbar() plt.subplot(1, 2, 1) plt.imshow(noisy_data.as_array()) plt.title('Noisy Data') plt.colorbar() plt.show() # Create Operators op11 = Gradient(ig) op12 = Identity(op11.range_geometry()) op22 = SymmetrizedGradient(op11.domain_geometry()) op21 = ZeroOperator(ig, op22.range_geometry())
while i < vert: if vert > 1: x = Phantom.subset(vertical=i).array else: x = Phantom.array x[round(N / 4):round(3 * N / 4), round(N / 4):round(3 * N / 4)] = 0.5 x[round(N / 8):round(7 * N / 8), round(3 * N / 8):round(5 * N / 8)] = 0.98 if vert > 1: Phantom.fill(x, vertical=i) i += 1 # Display slice of phantom if vert > 1: plt.imshow(Phantom.subset(vertical=0).as_array()) else: plt.imshow(Phantom.as_array()) plt.show() # Set up AcquisitionGeometry object to hold the parameters of the measurement # setup geometry: # Number of angles, the actual angles from 0 to # pi for parallel beam, set the width of a detector # pixel relative to an object pixe and the number of detector pixels. angles_num = 20 det_w = 1.0 det_num = N angles = np.linspace(0,np.pi,angles_num,endpoint=False,dtype=np.float32)*\ 180/np.pi # Inputs: Geometry, 2D or 3D, angles, horz detector pixel count, # horz detector pixel size, vert detector pixel count,
data = loader.load(TestData.SHAPES) ig = data.geometry ag = ig noisy_data = ImageData( TestData.random_noise(data.as_array(), mode='gaussian', seed=1)) #noisy_data = ImageData(data.as_array()) # Show Ground Truth and Noisy Data plt.figure(figsize=(10, 10)) plt.subplot(2, 1, 1) plt.imshow(data.as_array()) plt.title('Ground Truth') plt.colorbar() plt.subplot(2, 1, 2) plt.imshow(noisy_data.as_array()) plt.title('Noisy Data') plt.colorbar() plt.show() # Setup and run the regularised CGLS algorithm (Tikhonov with Gradient) x_init = ig.allocate() alpha = 2 op = Gradient(ig) block_op = BlockOperator(Identity(ig), alpha * op, shape=(2, 1)) block_data = BlockDataContainer(noisy_data, op.range_geometry().allocate()) cgls = CGLS(x_init=x_init, operator=block_op, data=block_data) cgls.max_iteration = 200 cgls.update_objective_interval = 5
# Create noisy data. Apply Gaussian noise ig = ImageGeometry(voxel_num_x=N, voxel_num_y=N, voxel_num_z=N) ag = ig n1 = TestData.random_noise(phantom_tm, mode='gaussian', mean=0, var=0.001, seed=10) noisy_data = ImageData(n1) # Show results sliceSel = int(0.5 * N) plt.figure(figsize=(15, 15)) plt.subplot(3, 1, 1) plt.imshow(noisy_data.as_array()[sliceSel, :, :], vmin=0, vmax=1) plt.title('Axial View') plt.colorbar() plt.subplot(3, 1, 2) plt.imshow(noisy_data.as_array()[:, sliceSel, :], vmin=0, vmax=1) plt.title('Coronal View') plt.colorbar() plt.subplot(3, 1, 3) plt.imshow(noisy_data.as_array()[:, :, sliceSel], vmin=0, vmax=1) plt.title('Sagittal View') plt.colorbar() plt.show() # Regularisation Parameter alpha = 0.05
from ccpi.astra.ops import AstraProjectorSimple import numpy as np import matplotlib.pyplot as plt # Choose either a parallel-beam (1=parallel2D) or fan-beam (2=cone2D) test case test_case = 1 # Set up phantom size NxN by creating ImageGeometry, initialising the # ImageData object with this geometry and empty array and finally put some # data into its array, and display as image. N = 128 ig = ImageGeometry(voxel_num_x=N, voxel_num_y=N) Phantom = ImageData(geometry=ig) x = Phantom.as_array() x[round(N / 4):round(3 * N / 4), round(N / 4):round(3 * N / 4)] = 0.5 x[round(N / 8):round(7 * N / 8), round(3 * N / 8):round(5 * N / 8)] = 1 plt.imshow(x) plt.title('Phantom image') plt.show() # Set up AcquisitionGeometry object to hold the parameters of the measurement # setup geometry: # Number of angles, the actual angles from 0 to # pi for parallel beam and 0 to 2pi for fanbeam, set the width of a detector # pixel relative to an object pixel, the number of detector pixels, and the # source-origin and origin-detector distance (here the origin-detector distance # set to 0 to simulate a "virtual detector" with same detector pixel size as # object pixel size). angles_num = 20
#%% # Show Ground Truth/Noisy Data & BackProjection from mpl_toolkits.axes_grid1 import make_axes_locatable def colorbar(mappable): ax = mappable.axes fig = ax.figure divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.15) return fig.colorbar(mappable, cax=cax) fig, ax = plt.subplots(1, 3) img1 = ax[0].imshow(data.as_array()) ax[0].set_title('Ground Truth') colorbar(img1) img2 = ax[1].imshow(noisy_data.as_array()) ax[1].set_title('Projection Data') colorbar(img2) img3 = ax[2].imshow(back_proj.as_array()) ax[2].set_title('BackProjection') colorbar(img3) plt.tight_layout(h_pad=1.5) fig1, ax1 = plt.subplots(1, 3) img4 = ax1[0].imshow(fista.get_output().as_array()) ax1[0].set_title('LS unconstrained') colorbar(img4) img5 = ax1[1].imshow(fista0.get_output().as_array())
plt.loglog(iternum[[0,-1]],[objective1.value, objective1.value], label='CVX LS+1') plt.loglog(iternum,criter1,label='FISTA LS+1') plt.loglog(iternum,criterfbpd1,label='FBPD LS+1') plt.legend() plt.show() # Now try 1-norm and TV denoising with FBPD, first 1-norm. # Set up phantom size NxN by creating ImageGeometry, initialising the # ImageData object with this geometry and empty array and finally put some # data into its array, and display as image. N = 64 ig = ImageGeometry(voxel_num_x=N,voxel_num_y=N) Phantom = ImageData(geometry=ig) x = Phantom.as_array() x[round(N/4):round(3*N/4),round(N/4):round(3*N/4)] = 0.5 x[round(N/8):round(7*N/8),round(3*N/8):round(5*N/8)] = 1 plt.imshow(x) plt.title('Phantom image') plt.show() # Identity operator for denoising I = TomoIdentity(ig) # Data and add noise y = I.direct(Phantom) y.array = y.array + 0.1*np.random.randn(N, N) plt.imshow(y.array)
from ccpi.optimisation.operators import BlockOperator, Gradient, Identity from ccpi.optimisation.functions import L2NormSquared, L1Norm, \ FunctionOperatorComposition, BlockFunction, ZeroFunction # Create Ground truth and Noisy data N = 100 data = np.zeros((N, N)) data[round(N / 4):round(3 * N / 4), round(N / 4):round(3 * N / 4)] = 0.5 data[round(N / 8):round(7 * N / 8), round(3 * N / 8):round(5 * N / 8)] = 1 data = ImageData(data) ig = ImageGeometry(voxel_num_x=N, voxel_num_y=N) ag = ig n1 = TestData.random_noise(data.as_array(), mode='s&p', salt_vs_pepper=0.9, amount=0.2) noisy_data = ImageData(n1) # Regularisation Parameter alpha = 5 ############################################################################### # Setup and run the FISTA algorithm operator = Gradient(ig) fidelity = L1Norm(b=noisy_data) regulariser = FunctionOperatorComposition(alpha * L2NormSquared(), operator) x_init = ig.allocate()
n1 = TestData.random_noise(data.as_array() / scale, mode=noise, seed=10) * scale elif noise == 'gaussian': n1 = TestData.random_noise(data.as_array(), mode=noise, seed=10) else: raise ValueError('Unsupported Noise ', noise) noisy_data = ImageData(n1) # Show Ground Truth and Noisy Data plt.figure(figsize=(10, 5)) plt.subplot(1, 2, 1) plt.imshow(data.as_array()) plt.title('Ground Truth') plt.colorbar() plt.subplot(1, 2, 2) plt.imshow(noisy_data.as_array()) plt.title('Noisy Data') plt.colorbar() plt.show() # Regularisation Parameter depending on the noise distribution if noise == 's&p': alpha = 0.8 elif noise == 'poisson': alpha = .3 elif noise == 'gaussian': alpha = .2 beta = 2 * alpha # Fidelity
plt.imshow(cgls.get_output().as_array()) plt.colorbar() plt.title('CGLS reconstruction') plt.subplot(2, 2, 2) plt.imshow(fista.get_output().as_array()) plt.colorbar() plt.title('FISTA reconstruction') plt.subplot(2, 2, 3) plt.imshow(pdhg.get_output().as_array()) plt.colorbar() plt.title('PDHG reconstruction') plt.subplot(2, 2, 4) plt.imshow(recon_cgls_astra.as_array()) plt.colorbar() plt.title('CGLS astra') plt.show() diff1 = pdhg.get_output() - recon_cgls_astra diff2 = fista.get_output() - recon_cgls_astra diff3 = cgls.get_output() - recon_cgls_astra plt.figure(figsize=(15, 15)) plt.subplot(3, 1, 1) plt.imshow(diff1.abs().as_array()) plt.title('Diff PDHG vs CGLS astra') plt.colorbar()