2828
2929from unittest .mock import Mock
3030
31+ from tomobar .methodsDIR import RecToolsDIR
32+
3133if cupy_run :
3234 from tomobar .methodsDIR_CuPy import RecToolsDIRCuPy
3335 from tomobar .methodsIR_CuPy import RecToolsIRCuPy
4042
4143
4244__all__ = [
45+ "FBP2d_astra" ,
4346 "FBP" ,
44- "LPRec" ,
4547 "SIRT" ,
4648 "CGLS" ,
49+ "LPRec" ,
4750]
4851
4952input_data_axis_labels = ["angles" , "detY" , "detX" ] # set the labels of the input data
5053
5154
55+ ## %%%%%%%%%%%%%%%%%%%%%%% FBP2d_astra reconstruction %%%%%%%%%%%%%%%%%%%%%%%%%%%% ##
56+ def FBP2d_astra (
57+ data : np .ndarray ,
58+ angles : np .ndarray ,
59+ center : Optional [float ] = None ,
60+ filter_type : str = "ram-lak" ,
61+ filter_parameter : Optional [float ] = None ,
62+ filter_d : Optional [float ] = None ,
63+ recon_size : Optional [int ] = None ,
64+ recon_mask_radius : float = 0.95 ,
65+ neglog : bool = False ,
66+ gpu_id : int = 0 ,
67+ ) -> np .ndarray :
68+ """
69+ Perform Filtered Backprojection (FBP) reconstruction slice-by-slice (2d) using ASTRA toolbox :cite:`van2016fast` and
70+ ToMoBAR :cite:`kazantsev2020tomographic` wrappers.
71+ This is a 2D recon using ASTRA's API for the FBP method, see for more parameters ASTRA's documentation here:
72+ https://astra-toolbox.com/docs/algs/FBP_CUDA.html.
73+
74+ Parameters`
75+ ----------
76+ data : np.ndarray
77+ Projection data as a 3d numpy array.
78+ angles : np.ndarray
79+ An array of angles given in radians.
80+ center : float, optional
81+ The center of rotation (CoR).
82+ filter_type: str
83+ Type of projection filter, see ASTRA's API for all available options for filters.
84+ filter_parameter: float, optional
85+ Parameter value for the 'tukey', 'gaussian', 'blackman' and 'kaiser' filter types.
86+ filter_d: float, optional
87+ D parameter value for 'shepp-logan', 'cosine', 'hamming' and 'hann' filter types.
88+ recon_size : int, optional
89+ The [recon_size, recon_size] shape of the reconstructed slice in pixels.
90+ By default (None), the reconstructed size will be the dimension of the horizontal detector.
91+ recon_mask_radius: float
92+ The radius of the circular mask that applies to the reconstructed slice in order to crop
93+ out some undesirable artifacts. The values outside the given diameter will be set to zero.
94+ It is recommended to keep the value in the range [0.7-1.0].
95+ neglog: bool
96+ Take negative logarithm on input data to convert to attenuation coefficient or a density of the scanned object. Defaults to False,
97+ assuming that the negative log is taken either in normalisation procedure on with Paganin filter application.
98+ gpu_id : int
99+ A GPU device index to perform operation on.
100+
101+ Returns
102+ -------
103+ np.ndarray
104+ The FBP reconstructed volume as a numpy array.
105+ """
106+ data_shape = np .shape (data )
107+ if recon_size is None :
108+ recon_size = data_shape [2 ]
109+
110+ RecTools = _instantiate_direct_recon2d_class (
111+ data , angles , center , recon_size , gpu_id
112+ )
113+
114+ detY_size = data_shape [1 ]
115+ reconstruction = np .empty (
116+ (recon_size , detY_size , recon_size ), dtype = np .float32 (), order = "C"
117+ )
118+ _take_neg_log_np (data ) if neglog else data
119+
120+ # loop over detY slices
121+ for slice_index in range (0 , detY_size ):
122+ reconstruction [:, slice_index , :] = RecTools .FBP (
123+ data [:, slice_index , :],
124+ filter_type = filter_type ,
125+ filter_parameter = filter_parameter ,
126+ filter_d = filter_d ,
127+ recon_mask_radius = recon_mask_radius ,
128+ )
129+ return reconstruction
130+
131+
52132## %%%%%%%%%%%%%%%%%%%%%%% FBP reconstruction %%%%%%%%%%%%%%%%%%%%%%%%%%%% ##
53133def FBP (
54134 data : cp .ndarray ,
@@ -68,7 +148,7 @@ def FBP(
68148 Parameters
69149 ----------
70150 data : cp.ndarray
71- Projection data as a CuPy array.
151+ Projection data as a 3d CuPy array.
72152 angles : np.ndarray
73153 An array of angles given in radians.
74154 center : float, optional
@@ -124,7 +204,7 @@ def LPRec(
124204 Parameters
125205 ----------
126206 data : cp.ndarray
127- Projection data as a CuPy array.
207+ Projection data as a 3d CuPy array.
128208 angles : np.ndarray
129209 An array of angles given in radians.
130210 center : float, optional
@@ -315,6 +395,43 @@ def _instantiate_direct_recon_class(
315395 return RecToolsCP
316396
317397
398+ ## %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ##
399+ def _instantiate_direct_recon2d_class (
400+ data : np .ndarray ,
401+ angles : np .ndarray ,
402+ center : Optional [float ] = None ,
403+ recon_size : Optional [int ] = None ,
404+ gpu_id : int = 0 ,
405+ ) -> Type :
406+ """instantiate ToMoBAR's direct recon class for 2d reconstruction
407+
408+ Args:
409+ data (cp.ndarray): data array
410+ angles (np.ndarray): angles
411+ center (Optional[float], optional): center of recon. Defaults to None.
412+ recon_size (Optional[int], optional): recon_size. Defaults to None.
413+ gpu_id (int, optional): gpu ID. Defaults to 0.
414+
415+ Returns:
416+ Type[RecToolsDIR]: an instance of the direct recon class
417+ """
418+ if center is None :
419+ center = data .shape [2 ] // 2 # making a crude guess
420+ if recon_size is None :
421+ recon_size = data .shape [2 ]
422+ RecTools = RecToolsDIR (
423+ DetectorsDimH = data .shape [2 ], # Horizontal detector dimension
424+ DetectorsDimV = None , # 2d case
425+ CenterRotOffset = data .shape [2 ] / 2
426+ - center
427+ - 0.5 , # Center of Rotation scalar or a vector
428+ AnglesVec = - angles , # A vector of projection angles in radians
429+ ObjSize = recon_size , # Reconstructed object dimensions (scalar)
430+ device_projector = gpu_id ,
431+ )
432+ return RecTools
433+
434+
318435def _instantiate_iterative_recon_class (
319436 data : cp .ndarray ,
320437 angles : np .ndarray ,
@@ -361,3 +478,12 @@ def _take_neg_log(data: cp.ndarray) -> cp.ndarray:
361478 data [cp .isnan (data )] = 6.0
362479 data [cp .isinf (data )] = 0
363480 return data
481+
482+
483+ def _take_neg_log_np (data : np .ndarray ) -> np .ndarray :
484+ """Taking negative log"""
485+ data [data <= 0 ] = 1
486+ data = - np .log (data )
487+ data [np .isnan (data )] = 6.0
488+ data [np .isinf (data )] = 0
489+ return data
0 commit comments