def test_resizing_op_call(odl_tspace_impl): impl = odl_tspace_impl dtypes = [ dt for dt in tensor_space_impl(impl).available_dtypes() if is_numeric_dtype(dt) ] for dtype in dtypes: # Minimal test since this operator only wraps resize_array space = odl.uniform_discr([0, -1], [1, 1], (4, 5), impl=impl) res_space = odl.uniform_discr([0, -0.6], [2, 0.2], (8, 2), impl=impl) res_op = odl.ResizingOperator(space, res_space) out = res_op(space.one()) true_res = np.zeros((8, 2)) true_res[:4, :] = 1 assert np.array_equal(out, true_res) out = res_space.element() res_op(space.one(), out=out) assert np.array_equal(out, true_res) # Test also mapping to default impl for other 'impl' if impl != 'numpy': space = odl.uniform_discr([0, -1], [1, 1], (4, 5), impl=impl) res_space = odl.uniform_discr([0, -0.6], [2, 0.2], (8, 2)) res_op = odl.ResizingOperator(space, res_space) out = res_op(space.one()) true_res = np.zeros((8, 2)) true_res[:4, :] = 1 assert np.array_equal(out, true_res) out = res_space.element() res_op(space.one(), out=out) assert np.array_equal(out, true_res)
def test_resizing_op_mixed_uni_nonuni(): """Check if resizing along uniform axes in mixed discretizations works.""" nonuni_part = odl.nonuniform_partition([0, 1, 4]) uni_part = odl.uniform_partition(-1, 1, 4) part = uni_part.append(nonuni_part, uni_part, nonuni_part) fspace = odl.FunctionSpace(odl.IntervalProd(part.min_pt, part.max_pt)) tspace = odl.rn(part.shape) space = odl.DiscreteLp(fspace, part, tspace) # Keep non-uniform axes fixed res_op = odl.ResizingOperator(space, ran_shp=(6, 3, 6, 3)) assert res_op.axes == (0, 2) assert res_op.offset == (1, 0, 1, 0) # Evaluation test with a simpler case part = uni_part.append(nonuni_part) fspace = odl.FunctionSpace(odl.IntervalProd(part.min_pt, part.max_pt)) tspace = odl.rn(part.shape) space = odl.DiscreteLp(fspace, part, tspace) res_op = odl.ResizingOperator(space, ran_shp=(6, 3)) result = res_op(space.one()) true_result = [[0, 0, 0], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [0, 0, 0]] assert np.array_equal(result, true_result) # Test adjoint elem = noise_element(space) res_elem = noise_element(res_op.range) inner1 = res_op(elem).inner(res_elem) inner2 = elem.inner(res_op.adjoint(res_elem)) assert almost_equal(inner1, inner2)
def __init__(self, filter_space, data_space, det_space, w_detv, g_w, a_wc): odl.Operator.__init__(self, domain=filter_space, range=data_space, linear=True) self.rs_detu = int(2**(np.ceil(np.log2(filter_space.size)) + 1)) # set =filter.size if filter is twice the detector self.frs_detu = self.rs_detu // 2 + 1 self.rs_filt = odl.ResizingOperator(filter_space, ran_shp=(self.rs_detu, )) self.gw = np.asarray(g_w) self.a_wc = a_wc self.w_detv = w_detv # self.rs_filt.domain.weighting.const self.det_tr_space = odl.uniform_discr( [det_space.min_pt[1], det_space.min_pt[0]], [det_space.max_pt[1], det_space.max_pt[0]], (np.size(det_space, 1), np.size(det_space, 0))) self.rs_det = odl.ResizingOperator(self.det_tr_space, ran_shp=(np.size(self.range, 2), self.rs_detu)) self.flt = 'float32' self.clx = 'complex64' self.flt1 = 'float64' self.clx1 = 'complex128' thrds = 8 self.d_a = pyfftw.empty_aligned((np.size(self.range, 2), self.rs_detu), dtype=self.flt) self.d_b = pyfftw.empty_aligned( (np.size(self.range, 2), self.frs_detu), dtype=self.clx) self.fft_d = pyfftw.FFTW(self.d_a, self.d_b, axes=(1, ), threads=thrds) self.id_a = pyfftw.empty_aligned( (np.size(self.range, 2), self.frs_detu), dtype=self.clx) self.id_b = pyfftw.empty_aligned( (np.size(self.range, 2), self.rs_detu), dtype=self.flt) self.ifft_d = pyfftw.FFTW(self.id_a, self.id_b, axes=(1, ), threads=thrds, direction='FFTW_BACKWARD') self.f_a = pyfftw.empty_aligned(self.rs_detu, dtype=self.flt) self.f_b = pyfftw.empty_aligned(self.frs_detu, dtype=self.clx) self.fft_f = pyfftw.FFTW(self.f_a, self.f_b) self.if_a = pyfftw.empty_aligned(self.frs_detu, dtype=self.clx1) self.if_b = pyfftw.empty_aligned(self.rs_detu, dtype=self.flt1) self.ifft_f = pyfftw.FFTW(self.if_a, self.if_b, direction='FFTW_BACKWARD')
def test_resizing_op_adjoint(padding, odl_tspace_impl): impl = odl_tspace_impl pad_mode, pad_const = padding dtypes = [ dt for dt in tensor_space_impl(impl).available_dtypes() if is_real_floating_dtype(dt) ] for dtype in dtypes: space = odl.uniform_discr([0, -1], [1, 1], (4, 5), dtype=dtype, impl=impl) res_space = odl.uniform_discr([0, -1.4], [1.5, 1.4], (6, 7), dtype=dtype, impl=impl) res_op = odl.ResizingOperator(space, res_space, pad_mode=pad_mode, pad_const=pad_const) if pad_const != 0.0: with pytest.raises(NotImplementedError): res_op.adjoint return elem = noise_element(space) res_elem = noise_element(res_space) inner1 = res_op(elem).inner(res_elem) inner2 = elem.inner(res_op.adjoint(res_elem)) assert almost_equal(inner1, inner2, places=dtype_places(dtype))
def test_resizing_op_properties(odl_tspace_impl, padding): impl = odl_tspace_impl dtypes = [ dt for dt in tensor_space_impl(impl).available_dtypes() if is_numeric_dtype(dt) ] pad_mode, pad_const = padding for dtype in dtypes: # Explicit range space = odl.uniform_discr([0, -1], [1, 1], (10, 5), dtype=dtype) res_space = odl.uniform_discr([0, -3], [2, 3], (20, 15), dtype=dtype) res_op = odl.ResizingOperator(space, res_space, pad_mode=pad_mode, pad_const=pad_const) assert res_op.domain == space assert res_op.range == res_space assert res_op.offset == (0, 5) assert res_op.pad_mode == pad_mode assert res_op.pad_const == pad_const if pad_mode == 'constant' and pad_const != 0: assert not res_op.is_linear else: assert res_op.is_linear # Implicit range via ran_shp and offset res_op = odl.ResizingOperator(space, ran_shp=(20, 15), offset=[0, 5], pad_mode=pad_mode, pad_const=pad_const) assert np.allclose(res_op.range.min_pt, res_space.min_pt) assert np.allclose(res_op.range.max_pt, res_space.max_pt) assert np.allclose(res_op.range.cell_sides, res_space.cell_sides) assert res_op.range.dtype == res_space.dtype assert res_op.offset == (0, 5) assert res_op.pad_mode == pad_mode assert res_op.pad_const == pad_const if pad_mode == 'constant' and pad_const != 0: assert not res_op.is_linear else: assert res_op.is_linear
def test_resizing_op_deriv(padding): pad_mode, pad_const = padding space = odl.uniform_discr([0, -1], [1, 1], (4, 5)) res_space = odl.uniform_discr([0, -0.6], [2, 0.2], (8, 2)) res_op = odl.ResizingOperator(space, res_space, pad_mode=pad_mode, pad_const=pad_const) res_op_deriv = res_op.derivative(space.one()) if pad_mode == 'constant' and pad_const != 0: # Only non-trivial case is constant padding with const != 0 assert res_op_deriv.pad_mode == 'constant' assert res_op_deriv.pad_const == 0.0 else: assert res_op_deriv is res_op
def test_resizing_op_inverse(padding, odl_tspace_impl): impl = odl_tspace_impl pad_mode, pad_const = padding dtypes = [dt for dt in tensor_space_impl(impl).available_dtypes() if is_numeric_dtype(dt)] for dtype in dtypes: space = odl.uniform_discr([0, -1], [1, 1], (4, 5), dtype=dtype, impl=impl) res_space = odl.uniform_discr([0, -1.4], [1.5, 1.4], (6, 7), dtype=dtype, impl=impl) res_op = odl.ResizingOperator(space, res_space, pad_mode=pad_mode, pad_const=pad_const) # Only left inverse if the operator extends in all axes x = noise_element(space) assert res_op.inverse(res_op(x)) == x
def test_resizing_op_init(odl_tspace_impl, padding): # Test if the different init patterns run impl = odl_tspace_impl pad_mode, pad_const = padding space = odl.uniform_discr([0, -1], [1, 1], (10, 5), impl=impl) res_space = odl.uniform_discr([0, -3], [2, 3], (20, 15), impl=impl) odl.ResizingOperator(space, res_space) odl.ResizingOperator(space, ran_shp=(20, 15)) odl.ResizingOperator(space, ran_shp=(20, 15), offset=(0, 5)) odl.ResizingOperator(space, ran_shp=(20, 15), pad_mode=pad_mode) odl.ResizingOperator(space, ran_shp=(20, 15), pad_mode=pad_mode, pad_const=pad_const) odl.ResizingOperator(space, ran_shp=(20, 15), discr_kwargs={'nodes_on_bdry': True})
def test_resizing_op_inverse(padding, fn_impl): pad_mode, pad_const = padding dtypes = [ dt for dt in odl.FN_IMPLS[fn_impl].available_dtypes() if is_scalar_dtype(dt) ] for dtype in dtypes: space = odl.uniform_discr([0, -1], [1, 1], (4, 5), dtype=dtype, impl=fn_impl) res_space = odl.uniform_discr([0, -1.4], [1.5, 1.4], (6, 7), dtype=dtype, impl=fn_impl) res_op = odl.ResizingOperator(space, res_space, pad_mode=pad_mode, pad_const=pad_const) # Only left inverse if the operator extentds in all axes x = noise_element(space) assert res_op.inverse(res_op(x)) == x
def MTF_x(filts, voxels, angles, src_rad, det_rad): nVar, step = 6, 2 MTF_list = np.zeros((len(filts), voxels[0] // 2)) for k in range(nVar): DO = phantom(voxels, 'Plane_yz', angles, None, src_rad, det_rad, offset_x=step * k - (nVar // 2) * step) CTo = CT.CCB_CT(DO) CTo.init_algo() CTo.init_DDF_FDK() mid = voxels[0] // 2 pad_op = odl.ResizingOperator(DO.reco_space, ran_shp=(voxels[0] * 2, voxels[1], voxels[2])) tel = 0 for f in filts: if type(f) == list: PlSF_x = CTo.FDK.filt_LP('Shepp-Logan', f, compute_results='no') elif type(f) == str: PlSF_x = CTo.FDK.do(f, compute_results='no') else: PlSF_x = CTo.FDK_bin(f) MTF_x = pad_op.inverse( np.abs( np.fft.fftshift( np.fft.fftn(np.fft.ifftshift(pad_op(PlSF_x)))))) MTF_list[tel] += MTF_x[mid:, mid, mid] / MTF_x[mid, mid, mid] / nVar tel += 1 return MTF_list
def test_resizing_op_raise(): # domain not a uniformely discretized Lp with pytest.raises(TypeError): odl.ResizingOperator(odl.rn(5), ran_shp=(10, )) grid = odl.RectGrid([0, 2, 3]) part = odl.RectPartition(odl.IntervalProd(0, 3), grid) fspace = odl.FunctionSpace(odl.IntervalProd(0, 3)) dspace = odl.rn(3) space = odl.DiscreteLp(fspace, part, dspace) with pytest.raises(ValueError): odl.ResizingOperator(space, ran_shp=(10, )) # different cell sides in domain and range space = odl.uniform_discr(0, 1, 10) res_space = odl.uniform_discr(0, 1, 15) with pytest.raises(ValueError): odl.ResizingOperator(space, res_space) # non-integer multiple of cell sides used as shift (grid of the # resized space shifted) space = odl.uniform_discr(0, 1, 5) res_space = odl.uniform_discr(-0.5, 1.5, 10) with pytest.raises(ValueError): odl.ResizingOperator(space, res_space) # need either range or ran_shp with pytest.raises(ValueError): odl.ResizingOperator(space) # offset cannot be combined with range space = odl.uniform_discr([0, -1], [1, 1], (10, 5)) res_space = odl.uniform_discr([0, -3], [2, 3], (20, 15)) with pytest.raises(ValueError): odl.ResizingOperator(space, res_space, offset=(0, 0)) # bad pad_mode with pytest.raises(ValueError): odl.ResizingOperator(space, res_space, pad_mode='something')
class TranslationCostFixedTemplNum(TranslationCostFixedTempl): @property def gradient(self): step = 2 * max(self.f.space.cell_sides) return odl.solvers.NumericalGradient(self, step=step) # %% Testing space = odl.uniform_discr([-1, -1, -1], [1, 1, 1], (150, 150, 150), interp='linear') templ = odl.phantom.shepp_logan(space, modified=True) # Make a bit bigger to avoid hitting the boundary resize = odl.ResizingOperator(space, ran_shp=(256, 256, 256)) templ = resize(templ) true_t = (0.5, -0.5, 0.5) templ_shifted = TranslationOperatorFixedTempl(templ)(true_t) templ.show() templ_shifted.show() # Define spaces of different resolutions space_hires = resize.range space_midres = odl.uniform_discr(space_hires.min_pt, space_hires.max_pt, shape=(128, 128, 128)) space_lowres = odl.uniform_discr(space_hires.min_pt, space_hires.max_pt, shape=(32, 32, 32))
def Create_dataset_ASTRA_real(dataset, pix_size, src_rad, det_rad, ang_freq, Exp_bin, bin_param, vox=None, vecs=None): # ! ! ! We overide 'vox' and 'vecs' later on # The size of the measured objects in voxels data_obj = ddf.real_data(dataset, pix_size, src_rad, det_rad, ang_freq, vox=vox, vecs=vecs) g = np.ascontiguousarray(np.transpose(np.asarray(data_obj.g.copy()), (2, 0, 1)), dtype=np.float32) v, ang, u = g.shape if vox is None: voxels = data_obj.voxels else: voxels = [vox, vox, vox] MaxVoxDataset = np.max([int(voxels[0]**3 * 0.005), 5 * 10**6]) Smat = Make_Smat(voxels, MaxVoxDataset, '', real_data=dataset['mask']) # %% Create geometry geom = data_obj.geometry w_du = data_obj.pix_size dpix = [u, v] minvox = data_obj.reco_space.min_pt[0] maxvox = data_obj.reco_space.max_pt[0] vox = np.shape(data_obj.reco_space)[0] vol_geom = astra.create_vol_geom(vox, vox, vox, minvox, maxvox, minvox, maxvox, minvox, maxvox) # Build a vecs vector from the geometry, or load it if type(geom) == np.ndarray: vecs = geom proj_geom = astra.create_proj_geom('cone_vec', v, u, vecs) elif type(geom) == odl.tomo.geometry.conebeam.ConeFlatGeometry: angles = np.linspace((1 / ang) * np.pi, (2 + 1 / ang) * np.pi, ang, False) w_du, w_dv = 2 * data_obj.geometry.detector.partition.max_pt / [u, v] proj_geom = astra.create_proj_geom('cone', w_dv, w_du, v, u, angles, data_obj.geometry.src_radius, data_obj.geometry.det_radius) filter_part = odl.uniform_partition(-data_obj.detecsize[0], data_obj.detecsize[0], dpix[0]) filter_space = odl.uniform_discr_frompartition(filter_part, dtype='float64') spf_space, Exp_op = ddf.ExpOp_builder(bin_param, filter_space, interp=Exp_bin) nParam = np.size(spf_space) fullFilterSize = int(2**(np.ceil(np.log2(dpix[0])) + 1)) halfFilterSize = fullFilterSize // 2 + 1 Resize_Op = odl.ResizingOperator(Exp_op.range, ran_shp=(fullFilterSize, )) # %% Create projection and reconstion objects proj_id = astra.data3d.link('-proj3d', proj_geom, g) rec = np.zeros(astra.geom_size(vol_geom), dtype=np.float32) rec_id = astra.data3d.link('-vol', vol_geom, rec) B = np.zeros((MaxVoxDataset, nParam + 1)) # %% Make the matrix columns of the matrix B for nP in range(nParam): unit_vec = spf_space.zero() unit_vec[nP] = 1 filt = Exp_op(unit_vec) rs_filt = Resize_Op(filt) f_filt = np.real(np.fft.rfft(np.fft.ifftshift(rs_filt))) filter2d = np.zeros((ang, halfFilterSize)) for i in range(ang): filter2d[i, :] = f_filt * 4 * w_du # %% Make a filter geometry filter_geom = astra.create_proj_geom('parallel', w_du, halfFilterSize, np.zeros(ang)) filter_id = astra.data2d.create('-sino', filter_geom, filter2d) # cfg = astra.astra_dict('FDK_CUDA') cfg['ReconstructionDataId'] = rec_id cfg['ProjectionDataId'] = proj_id cfg['option'] = {'FilterSinogramId': filter_id} # Create the algorithm object from the configuration structure alg_id = astra.algorithm.create(cfg) # %% astra.algorithm.run(alg_id) rec = np.transpose(rec, (2, 1, 0)) B[:, nP] = rec[Smat] # %% # Clean up. Note that GPU memory is tied up in the algorithm object, # and main RAM in the data objects. B[:, -1] = data_obj.f[Smat] astra.algorithm.delete(alg_id) astra.data3d.delete(rec_id) astra.data3d.delete(proj_id) return B
def NNFDK_astra(g, NW, geom, reco_space, w_du, Exp_op, node_output, ang_freq=None): # %% Create geometry # Make a circular scanning geometry ang, u, v = g.shape minvox = reco_space.min_pt[0] maxvox = reco_space.max_pt[0] vox = np.shape(reco_space)[0] vol_geom = astra.create_vol_geom(vox, vox, vox, minvox, maxvox, minvox, maxvox, minvox, maxvox) if type(geom) == np.ndarray: vecs = geom proj_geom = astra.create_proj_geom('cone_vec', v, u, vecs) elif type(geom) == odl.tomo.geometry.conebeam.ConeFlatGeometry: angles = np.linspace((1 / ang) * np.pi, (2 + 1 / ang) * np.pi, ang, False) w_du, w_dv = 2 * geom.detector.partition.max_pt / [u, v] proj_geom = astra.create_proj_geom('cone', w_dv, w_du, v, u, angles, geom.src_radius, geom.det_radius) g = np.transpose(np.asarray(g), (2, 0, 1)) # %% proj_id = astra.data3d.create('-proj3d', proj_geom, g) rec = np.zeros(astra.geom_size(vol_geom), dtype=np.float32) rec_tot = np.zeros(astra.geom_size(vol_geom), dtype=np.float32) rec_id = astra.data3d.link('-vol', vol_geom, rec) fullFilterSize = int(2**(np.ceil(np.log2(u)) + 1)) halfFilterSize = fullFilterSize // 2 + 1 filter2d = np.zeros((ang, halfFilterSize)) Resize_Op = odl.ResizingOperator(Exp_op.range, ran_shp=(fullFilterSize, )) # %% Make a filter geometry filter_geom = astra.create_proj_geom('parallel', w_du, halfFilterSize, np.zeros(ang)) cfg = astra.astra_dict('FDK_CUDA') cfg['ReconstructionDataId'] = rec_id cfg['ProjectionDataId'] = proj_id # Create the algorithm object from the configuration structure # %% # Set a container list for the learned filters h_e = [] if node_output: mid = v // 2 node_output_axis = [] for i in range(NW['nNodes']): h = NW['l1'][:-1, i] * 2 * NW['sc1'][0, :] h_e += [h] b = NW['l1'][-1, i] + np.sum( NW['l1'][:-1, i]) + 2 * np.dot(NW['l1'][:-1, i], NW['sc1'][1, :]) filter2d = Exp_op_FFT(Exp_op, h, filter2d, Resize_Op, w_du) filter_id = astra.data2d.create('-sino', filter_geom, filter2d) cfg['option'] = {'FilterSinogramId': filter_id} alg_id = astra.algorithm.create(cfg) astra.algorithm.run(alg_id) rec_tot = hidden_layer(rec, rec_tot, NW['l2'][i], b) if node_output: rec2 = hidden_layer(rec, 0, NW['l2'][i], b) node_output_axis += [ rec2[:, :, mid], rec2[:, mid, :], rec2[mid, :, :] ] # Make a numpy array of the filter list h_e = np.asarray(h_e) # b_o = self.network['l2'][-1] rec_tot = outer_layer(rec_tot, NW['l2'][-1], NW['sc2'][0], NW['sc2'][1]) rec_tot = np.transpose(rec_tot, (2, 1, 0)) # %% Make the matrix columns of the matrix B # %% # Clean up. Note that GPU memory is tied up in the algorithm object, # and main RAM in the data objects. astra.algorithm.delete(alg_id) astra.data3d.delete(rec_id) astra.data3d.delete(proj_id) if node_output: return rec_tot, h_e, node_output_axis else: return rec_tot, h_e
def Create_dataset_ASTRA_sim(pix, phantom, angles, src_rad, noise, Exp_bin, bin_param, **kwargs): if phantom == 'Defrise': phantom = 'Defrise random' if phantom == 'Fourshape_test': phantom = 'Fourshape' if 'MaxVoxDataset' in kwargs: MaxVoxDataset = kwargs['MaxVoxDataset'] else: MaxVoxDataset = np.max([int(pix**3 * 0.005), 1 * 10**6]) # The size of the measured objects in voxels voxels = [pix, pix, pix] dpix = [voxels[0] * 2, voxels[1]] u, v = dpix # ! ! ! This will lead to some problems later on ! ! ! det_rad = 0 data_obj = ddf.phantom(voxels, phantom, angles, noise, src_rad, det_rad, compute_xHQ=True) WV_obj = ddf.support_functions.working_var_map() WV_path = WV_obj.WV_path data_obj.make_mask(WV_path) Smat = Make_Smat(voxels, MaxVoxDataset, WV_path) # %% saving tiffs for CNNs w_du = data_obj.w_detu filt = make_hann_filt(voxels, w_du) xFDK = ddf.FDK_ODL_astra_backend.FDK_astra(data_obj.g, filt, data_obj.geometry, data_obj.reco_space, None) # %% Create geometry # Make a circular scanning geometry minvox = data_obj.reco_space.min_pt[0] maxvox = data_obj.reco_space.max_pt[0] vox = np.shape(data_obj.reco_space)[0] vol_geom = astra.create_vol_geom(vox, vox, vox, minvox, maxvox, minvox, maxvox, minvox, maxvox) ang = np.linspace((1 / angles) * np.pi, (2 + 1 / angles) * np.pi, angles, False) w_du, w_dv = 2 * data_obj.geometry.detector.partition.max_pt / [u, v] proj_geom = astra.create_proj_geom('cone', w_dv, w_du, v, u, ang, data_obj.geometry.src_radius, data_obj.geometry.det_radius) filter_part = odl.uniform_partition(-data_obj.detecsize[0], data_obj.detecsize[0], u) filter_space = odl.uniform_discr_frompartition(filter_part, dtype='float64') spf_space, Exp_op = ddf.support_functions.ExpOp_builder(bin_param, filter_space, interp=Exp_bin) nParam = np.size(spf_space) fullFilterSize = int(2**(np.ceil(np.log2(dpix[0])) + 1)) halfFilterSize = fullFilterSize // 2 + 1 Resize_Op = odl.ResizingOperator(Exp_op.range, ran_shp=(fullFilterSize, )) # %% Create forward and backward projector # project_id = astra.create_projector('cuda3d', proj_geom, vol_geom) # W = astra.OpTomo(project_id) # %% Create data proj_data = np.transpose(np.asarray(data_obj.g), (2, 0, 1)).copy() # W.FP(np.transpose(np.asarray(data_obj.f), (2, 1, 0))) # ! ! ! wat is deze? ! ! ! # if noise is not None: # g = add_poisson_noise(proj_data, noise[1]) # else: g = proj_data proj_id = astra.data3d.link('-sino', proj_geom, g) rec = np.zeros(astra.geom_size(vol_geom), dtype=np.float32) rec_id = astra.data3d.link('-vol', vol_geom, rec) B = np.zeros((MaxVoxDataset, nParam + 1)) # %% Make the matrix columns of the matrix B for nP in range(nParam): unit_vec = spf_space.zero() unit_vec[nP] = 1 filt = Exp_op(unit_vec) rs_filt = Resize_Op(filt) f_filt = np.real(np.fft.rfft(np.fft.ifftshift(rs_filt))) filter2d = np.zeros((angles, halfFilterSize)) for i in range(angles): filter2d[i, :] = f_filt * 4 * w_du # %% Make a filter geometry filter_geom = astra.create_proj_geom('parallel', w_du, halfFilterSize, np.zeros((angles))) filter_id = astra.data2d.create('-sino', filter_geom, filter2d) # cfg = astra.astra_dict('FDK_CUDA') cfg['ReconstructionDataId'] = rec_id cfg['ProjectionDataId'] = proj_id cfg['option'] = {'FilterSinogramId': filter_id} # Create the algorithm object from the configuration structure alg_id = astra.algorithm.create(cfg) # %% astra.algorithm.run(alg_id) rec = np.transpose(rec, (2, 1, 0)) B[:, nP] = rec[Smat] # %% # Clean up. Note that GPU memory is tied up in the algorithm object, # and main RAM in the data objects. B[:, -1] = data_obj.xHQ[Smat] # B[:, -1] = data_obj.f[Smat] astra.algorithm.delete(alg_id) astra.data3d.delete(rec_id) astra.data3d.delete(proj_id) return B, data_obj.xHQ, xFDK
impl='astra_cuda') # Phantom phantom_c = odl.phantom.shepp_logan(coarse_discr, modified=True) phantom_f = odl.phantom.shepp_logan(fine_discr, modified=True) # Define insert discretization using the fine cell sizes but the insert # min and max points insert_discr = odl.uniform_discr_fromdiscr( fine_discr, min_pt=insert_min_pt, max_pt=insert_max_pt, cell_sides=fine_discr.cell_sides) # Restrict the phantom to the insert discr resizing_operator = odl.ResizingOperator(fine_discr, insert_discr) phantom_insert = resizing_operator(phantom_f) # Ray trafo on the insert discretization only insert_ray_trafo = odl.tomo.RayTransform(insert_discr, geometry, impl='astra_cuda') # Forward operator = sum of masked coarse ray trafo and insert ray trafo sum_ray_trafo = odl.ReductionOperator(masked_coarse_ray_trafo, insert_ray_trafo) # Make phantom in the product space pspace = sum_ray_trafo.domain phantom = pspace.element([phantom_c, phantom_insert]) multigrid.graphics.show_both(*phantom)
# Calculate the FT only along the first axis. ft_op_axis0 = odl.trafos.FourierTransform(space, axes=0) phantom_ft_axis0 = ft_op_axis0(phantom) phantom_ft_axis0.show(title='Fourier transform along axis 0') # If a real space is used, the Fourier transform can be calculated in the # "half-complex" mode. This means that along the last axis of the transform, # only the negative half of the spectrum is stored since the other half is # its complex conjugate. This is faster and more memory efficient. real_space = space.real_space ft_op_halfc = odl.trafos.FourierTransform(real_space, halfcomplex=True) phantom_real = odl.phantom.shepp_logan(real_space, modified=True) phantom_real.show(title='Shepp-Logan phantom, real version') phantom_real_ft = ft_op_halfc(phantom_real) phantom_real_ft.show(title='Half-complex Fourier Transform') # If the space is real, the inverse also gives a real result. phantom_real_ft_inv = ft_op_halfc.inverse(phantom_real_ft) phantom_real_ft_inv.show(title='Half-complex Fourier Transform inverted', force_show=True) # The FT operator itself has no option of (zero-)padding, but it can be # composed with a `ResizingOperator` which does exactly that. Note that the # FT needs to be redefined on the enlarged space. padding_op = odl.ResizingOperator(space, ran_shp=(768, 768)) ft_op = odl.trafos.FourierTransform(padding_op.range) padded_ft_op = ft_op * padding_op phantom_ft_padded = padded_ft_op(phantom) phantom_ft_padded.show('Padded FT of the phantom')
angle = x[0] det_var = x[1] return np.sin(angle) * det_var def deriv1_ft(x): angle = x[0] det_var = x[1] return -np.cos(angle) * det_var # Fourier transform on the range of the FT along the detector axis, including # padding ran_shp = (ray_trafo.range.shape[0], ray_trafo.range.shape[1] * 2 - 1) resizing = odl.ResizingOperator(ray_trafo.range, ran_shp=ran_shp, pad_mode='order0') fourier = odl.trafos.FourierTransform(resizing.range, axes=1, impl='pyfftw') fourier = fourier * resizing # Ramp filter part alen = ray_trafo.geometry.motion_params.length ramp_filter = 1 / (2 * alen) * fourier.range.element(lambda x: abs(x[1])) # Smoothing filter (mollifier) for the reconstruction kernel (Fourier space) gaussian_ker = fourier.domain.element(gaussian_det, s=0.15) exp_filter = fourier(gaussian_ker) # Filters for lambda reconstruction lambda_filter_ft = fourier.range.element(lambda_ft) lambda_kernel_ft = exp_filter * ramp_filter * lambda_filter_ft