def test_radon2d_adjointness(self): # Set image size. m, n = 39, 23 # Define angles. angles = np.linspace(0, np.pi, 180, False) # Create operators. K, Kadj, ndet = radon.radon2d(m, n, angles) # Apply to dummy image. f = K(np.ones((m, n))) np.testing.assert_allclose(f.shape[0], angles.size) # Apply to dummy data. f = Kadj(np.ones_like(f)) np.testing.assert_allclose(f.shape, (m, n)) # Create random matrix. x = np.random.rand(m, n) p, q = K(x).shape # Create second random matrix. y = np.random.rand(p, q) # Check adjointness up to certain relative tolerance. np.testing.assert_allclose(np.dot(K(x).flatten(), y.flatten()), np.dot(x.flatten(), Kadj(y).flatten()), 1e-3)
def test_radon2d_plot(self): img = Image.open('data/phantom.png').convert('L') img = np.array(img) # Set image size. m, n = img.shape # Define angles. angles = np.linspace(0, np.pi, 180, False) # Create operators. K, Kadj, ndet = radon.radon2d(m, n, angles) # Plot original image. plt.imshow(img, cmap='gray') plt.colorbar() plt.show() # Apply to dummy image. f = K(img) # Plot data. plt.imshow(f, cmap='gray') plt.colorbar() plt.show() # Apply to dummy data. f = Kadj(f) # Plot result of backprojection. plt.imshow(f, cmap='gray') plt.colorbar() plt.show()
def test_radon2d_operators_cuda(self): # Define image size. image_size = (31, 23) # Define angles. nangles = 180 angles = np.linspace(0, np.pi, nangles, False) # Check if GPU is available. cuda = torch.cuda.is_available() device = torch.device('cuda') if cuda else 'cpu' # Create operators. R, Radj, ndet = radon.radon2d(*image_size, angles, cuda) data_size = (nangles, ndet) # Create instances for use with torch. K = radon.RadonTransform(R, Radj, data_size) Kadj = radon.BackProjection(R, Radj, image_size) # Create random matrix. x = torch.randn(1, 1, *image_size).to(device) # Create second random matrix. y = torch.randn(1, 1, *data_size).to(device) # Check adjointness up to certain relative tolerance. ip1 = torch.dot(K(x).flatten(), y.flatten()) ip2 = torch.dot(x.flatten(), Kadj(y).flatten()) torch.allclose(ip1, ip2)
def test_LinearOperator_radon_gradcheck(self): # Set image size. image_size = (5, 4) # Define angles. nangles = 180 angles = np.linspace(0, np.pi, nangles, False) # Create operators. R, Radj, ndet = radon.radon2d(*image_size, angles) data_size = (nangles, ndet) # Create instances for use with torch. K = radon.RadonTransform(R, Radj, data_size) Kadj = radon.BackProjection(R, Radj, image_size) # Apply to dummy input. x = torch.randn((1, 1, *image_size), requires_grad=True, dtype=torch.double) f = K(x) # Check for simple loss. loss = f.sum() loss.backward() torch.allclose(x.grad, Kadj(x.new_ones(1, 1, *data_size))) def op_fun(x): out = LinearOperator.apply(x, K, Kadj) return out.sum() # Check for anomalies. with tag.detect_anomaly(): x = torch.randn(1, 1, *image_size, requires_grad=True, dtype=torch.double) out = op_fun(x) out.backward() # Check numerical gradient up to certain tolerance. # Due to inaccuracy of adjoint this check fails. x = torch.randn(1, 1, *image_size, requires_grad=True, dtype=torch.double) tag.gradcheck(lambda t: K(t), x)
def test_radon2d(self): # Set image size. m, n = 39, 23 # Define angles. angles = np.linspace(0, np.pi, 180, False) # Create operators. K, Kadj, ndet = radon.radon2d(m, n, angles) # Apply to dummy image. f = K(np.ones((m, n))) np.testing.assert_allclose(f.shape[0], angles.size) # Apply to dummy data. f = Kadj(np.ones_like(f)) np.testing.assert_allclose(f.shape, (m, n))
def test_LinearOperator_radon_cuda(self): # Set image size. image_size = 5, 4 # Define angles. nangles = 180 angles = np.linspace(0, np.pi, nangles, False) # Check if GPU is available. cuda = torch.cuda.is_available() device = torch.device('cuda' if cuda else 'cpu') # Create operators. R, Radj, ndet = radon.radon2d(*image_size, angles, cuda) data_size = (nangles, ndet) # Create instances for use with torch. K = radon.RadonTransform(R, Radj, data_size) Kadj = radon.BackProjection(R, Radj, image_size) # Apply to dummy input. x = torch.randn((1, 1, *image_size), requires_grad=True, dtype=torch.double, device=device) f = K(x) # Check for simple loss. loss = f.sum() loss.backward() torch.allclose(x.grad, Kadj(x.new_ones(1, 1, *data_size))) def op_fun(x): out = LinearOperator.apply(x, K, Kadj) return out.sum() # Check for anomalies. with tag.detect_anomaly(): x = torch.randn(1, 1, *image_size, requires_grad=True, dtype=torch.double, device=device) out = op_fun(x) out.backward()
def setup_reconstruction_problem(image_size: tuple): """Set up reconstruction problem using Radon transform.""" # Define angles. nangles = 180 angles = np.linspace(0, np.pi, nangles, False) # Define Radon transform and adjoint. R, Radj, ndet = radon.radon2d(*image_size, angles) data_size = (nangles, ndet) # Create instances for use with torch. K = radon.RadonTransform(R, Radj, data_size) Kadj = radon.BackProjection(R, Radj, image_size) # Create data fidelity and its gradient. G, gradG = functionals.OpSqNormDataTerm(K, Kadj) return K, Kadj, G, gradG, data_size
def setup_reconstruction_problem(f: np.array, sigma: float): """Set up reconstruction problem using Radon transform.""" m, n = f.shape # Define angles. nangles = 180 angles = np.linspace(0, np.pi, nangles, False) # Define Radon transform and adjoint. K, Kadj, ndet = radon.radon2d(m, n, angles) # Generate data and add noise. y = K(f) # Add noise. ydelta = y + sigma**2 * y.var() * y.max() * np.random.randn(*y.shape) # Define data fidelity and its gradient. G, gradG = functionals.OpSqNormDataTerm(K, Kadj, ydelta) return ydelta, G, gradG
def landweber(): """Compute a solution by Landweber iteration.""" # Load phantom image. f = np.asarray(Image.open('data/phantom.png').convert('L'), dtype=np.double) f = f / np.max(f) m, n = f.shape # Define angles. angles = np.linspace(0, np.pi, 180, False) # Define Radon transform and adjoint. K, Kadj, ndet = radon.radon2d(m, n, angles) # Generate data and add noise. y = K(f) ydelta = y + 5 * np.random.randn(*y.shape) # Show image. plt.figure() plt.imshow(ydelta, cmap='gray') plt.colorbar() plt.show() # Initialise solution. x = np.zeros_like(f) # Define stepsize parameter. omega = 2e-5 # Run Landweber iteration. nliter = 30 for i in range(nliter): x = x - omega * Kadj(K(x) - ydelta) plt.figure() plt.imshow(x, cmap='gray') plt.colorbar() plt.show()