def test_fbp_reconstruction_filters(filter_type, frequency_scaling): """Validate that the various filters work as expected.""" apart = odl.uniform_partition(0, np.pi, 500) discr_reco_space = odl.uniform_discr([-20, -20], [20, 20], [100, 100], dtype='float32') # Geometry dpart = odl.uniform_partition(-30, 30, 500) geom = tomo.Parallel2dGeometry(apart, dpart) # Ray transform projector = tomo.RayTransform(discr_reco_space, geom, impl='astra_cuda') # Create Shepp-Logan phantom vol = odl.phantom.shepp_logan(projector.domain, modified=False) # Project data projections = projector(vol) # Create FBP operator with filters and apply to projections fbp_operator = odl.tomo.fbp_op(projector, filter_type=filter_type, frequency_scaling=frequency_scaling) fbp_result = fbp_operator(projections) maxerr = vol.norm() / 5.0 error = vol.dist(fbp_result) assert error < maxerr
def projector(request, dtype): n_angles = 200 geom, impl, angle = request.param.split() if angle == 'uniform': apart = odl.uniform_partition(0, 2 * np.pi, n_angles) elif angle == 'random': # Linearly spaced with random noise min_pt = 2 * (2.0 * np.pi) / n_angles max_pt = (2.0 * np.pi) - 2 * (2.0 * np.pi) / n_angles points = np.linspace(min_pt, max_pt, n_angles) points += np.random.rand(n_angles) * (max_pt - min_pt) / (5 * n_angles) apart = odl.nonuniform_partition(points) elif angle == 'nonuniform': # Angles spaced quadratically min_pt = 2 * (2.0 * np.pi) / n_angles max_pt = (2.0 * np.pi) - 2 * (2.0 * np.pi) / n_angles points = np.linspace(min_pt ** 0.5, max_pt ** 0.5, n_angles) ** 2 apart = odl.nonuniform_partition(points) else: raise ValueError('angle not valid') if geom == 'par2d': # Discrete reconstruction space discr_reco_space = odl.uniform_discr([-20, -20], [20, 20], [100, 100], dtype=dtype) # Geometry dpart = odl.uniform_partition(-30, 30, 200) geom = tomo.Parallel2dGeometry(apart, dpart) # Ray transform return tomo.RayTransform(discr_reco_space, geom, impl=impl) elif geom == 'par3d': # Discrete reconstruction space discr_reco_space = odl.uniform_discr([-20, -20, -20], [20, 20, 20], [100, 100, 100], dtype=dtype) # Geometry dpart = odl.uniform_partition([-30, -30], [30, 30], [200, 200]) geom = tomo.Parallel3dAxisGeometry(apart, dpart, axis=[1, 0, 0]) # Ray transform return tomo.RayTransform(discr_reco_space, geom, impl=impl) elif geom == 'cone2d': # Discrete reconstruction space discr_reco_space = odl.uniform_discr([-20, -20], [20, 20], [100, 100], dtype=dtype) # Geometry dpart = odl.uniform_partition(-30, 30, 200) geom = tomo.FanFlatGeometry(apart, dpart, src_radius=200, det_radius=100) # Ray transform return tomo.RayTransform(discr_reco_space, geom, impl=impl) elif geom == 'cone3d': # Discrete reconstruction space discr_reco_space = odl.uniform_discr([-20, -20, -20], [20, 20, 20], [100, 100, 100], dtype=dtype) # Geometry dpart = odl.uniform_partition([-30, -30], [30, 30], [200, 200]) geom = tomo.CircularConeFlatGeometry( apart, dpart, src_radius=200, det_radius=100, axis=[1, 0, 0]) # Ray transform return tomo.RayTransform(discr_reco_space, geom, impl=impl) elif geom == 'helical': # Discrete reconstruction space discr_reco_space = odl.uniform_discr([-20, -20, 0], [20, 20, 40], [100, 100, 100], dtype=dtype) # Geometry # TODO: angles n_angle = 700 apart = odl.uniform_partition(0, 8 * 2 * np.pi, n_angle) dpart = odl.uniform_partition([-30, -3], [30, 3], [200, 20]) geom = tomo.HelicalConeFlatGeometry(apart, dpart, pitch=5.0, src_radius=200, det_radius=100) # Ray transform return tomo.RayTransform(discr_reco_space, geom, impl=impl) else: raise ValueError('param not valid')