httomolibgpu 3.0__py3-none-any.whl → 3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- httomolibgpu/__init__.py +3 -1
- httomolibgpu/misc/denoise.py +30 -19
- httomolibgpu/misc/supp_func.py +1 -1
- httomolibgpu/prep/phase.py +55 -218
- httomolibgpu/prep/stripe.py +7 -3
- httomolibgpu/recon/algorithm.py +184 -41
- {httomolibgpu-3.0.dist-info → httomolibgpu-3.1.dist-info}/METADATA +1 -2
- {httomolibgpu-3.0.dist-info → httomolibgpu-3.1.dist-info}/RECORD +11 -12
- httomolibgpu/cuda_kernels/paganin_filter_gen.cu +0 -37
- {httomolibgpu-3.0.dist-info → httomolibgpu-3.1.dist-info}/WHEEL +0 -0
- {httomolibgpu-3.0.dist-info → httomolibgpu-3.1.dist-info}/licenses/LICENSE +0 -0
- {httomolibgpu-3.0.dist-info → httomolibgpu-3.1.dist-info}/top_level.txt +0 -0
httomolibgpu/__init__.py
CHANGED
|
@@ -4,11 +4,12 @@ from httomolibgpu.misc.morph import sino_360_to_180, data_resampler
|
|
|
4
4
|
from httomolibgpu.misc.rescale import rescale_to_int
|
|
5
5
|
from httomolibgpu.prep.alignment import distortion_correction_proj_discorpy
|
|
6
6
|
from httomolibgpu.prep.normalize import normalize
|
|
7
|
-
from httomolibgpu.prep.phase import
|
|
7
|
+
from httomolibgpu.prep.phase import paganin_filter_tomopy
|
|
8
8
|
from httomolibgpu.prep.stripe import (
|
|
9
9
|
remove_stripe_based_sorting,
|
|
10
10
|
remove_stripe_ti,
|
|
11
11
|
remove_all_stripe,
|
|
12
|
+
raven_filter,
|
|
12
13
|
)
|
|
13
14
|
|
|
14
15
|
from httomolibgpu.recon.algorithm import (
|
|
@@ -17,6 +18,7 @@ from httomolibgpu.recon.algorithm import (
|
|
|
17
18
|
LPRec3d_tomobar,
|
|
18
19
|
SIRT3d_tomobar,
|
|
19
20
|
CGLS3d_tomobar,
|
|
21
|
+
FISTA3d_tomobar,
|
|
20
22
|
)
|
|
21
23
|
|
|
22
24
|
from httomolibgpu.recon.rotation import find_center_vo, find_center_360, find_center_pc
|
httomolibgpu/misc/denoise.py
CHANGED
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
"""Module for data denoising. For more detailed information see :ref:`data_denoising_module`."""
|
|
22
22
|
|
|
23
23
|
import numpy as np
|
|
24
|
-
from typing import Union, Optional
|
|
25
24
|
|
|
26
25
|
from httomolibgpu import cupywrapper
|
|
27
26
|
|
|
@@ -33,7 +32,7 @@ from unittest.mock import Mock
|
|
|
33
32
|
from httomolibgpu.misc.supp_func import data_checker
|
|
34
33
|
|
|
35
34
|
if cupy_run:
|
|
36
|
-
from
|
|
35
|
+
from tomobar.regularisersCuPy import ROF_TV_cupy, PD_TV_cupy
|
|
37
36
|
else:
|
|
38
37
|
ROF_TV = Mock()
|
|
39
38
|
PD_TV = Mock()
|
|
@@ -47,10 +46,11 @@ __all__ = [
|
|
|
47
46
|
|
|
48
47
|
def total_variation_ROF(
|
|
49
48
|
data: cp.ndarray,
|
|
50
|
-
regularisation_parameter:
|
|
51
|
-
iterations:
|
|
52
|
-
time_marching_parameter:
|
|
53
|
-
gpu_id:
|
|
49
|
+
regularisation_parameter: float = 1e-05,
|
|
50
|
+
iterations: int = 3000,
|
|
51
|
+
time_marching_parameter: float = 0.001,
|
|
52
|
+
gpu_id: int = 0,
|
|
53
|
+
half_precision: bool = False,
|
|
54
54
|
) -> cp.ndarray:
|
|
55
55
|
"""
|
|
56
56
|
Total Variation using Rudin-Osher-Fatemi (ROF) :cite:`rudin1992nonlinear` explicit iteration scheme to perform edge-preserving image denoising.
|
|
@@ -62,14 +62,16 @@ def total_variation_ROF(
|
|
|
62
62
|
----------
|
|
63
63
|
data : cp.ndarray
|
|
64
64
|
Input CuPy 3D array of float32 data type.
|
|
65
|
-
regularisation_parameter : float
|
|
65
|
+
regularisation_parameter : float
|
|
66
66
|
Regularisation parameter to control the level of smoothing. Defaults to 1e-05.
|
|
67
|
-
iterations : int
|
|
67
|
+
iterations : int
|
|
68
68
|
The number of iterations. Defaults to 3000.
|
|
69
|
-
time_marching_parameter : float
|
|
69
|
+
time_marching_parameter : float
|
|
70
70
|
Time marching parameter, needs to be small to ensure convergence. Defaults to 0.001.
|
|
71
|
-
gpu_id : int
|
|
71
|
+
gpu_id : int
|
|
72
72
|
GPU device index to perform processing on. Defaults to 0.
|
|
73
|
+
half_precision : bool
|
|
74
|
+
Perform faster computation in half-precision with a very minimal sacrifice in quality. Defaults to False.
|
|
73
75
|
|
|
74
76
|
Returns
|
|
75
77
|
-------
|
|
@@ -84,19 +86,25 @@ def total_variation_ROF(
|
|
|
84
86
|
|
|
85
87
|
data = data_checker(data, verbosity=True, method_name="total_variation_ROF")
|
|
86
88
|
|
|
87
|
-
return
|
|
88
|
-
data,
|
|
89
|
+
return ROF_TV_cupy(
|
|
90
|
+
data,
|
|
91
|
+
regularisation_parameter,
|
|
92
|
+
iterations,
|
|
93
|
+
time_marching_parameter,
|
|
94
|
+
gpu_id,
|
|
95
|
+
half_precision,
|
|
89
96
|
)
|
|
90
97
|
|
|
91
98
|
|
|
92
99
|
def total_variation_PD(
|
|
93
100
|
data: cp.ndarray,
|
|
94
|
-
regularisation_parameter:
|
|
95
|
-
iterations:
|
|
96
|
-
isotropic:
|
|
97
|
-
nonnegativity:
|
|
98
|
-
lipschitz_const:
|
|
99
|
-
gpu_id:
|
|
101
|
+
regularisation_parameter: float = 1e-05,
|
|
102
|
+
iterations: int = 1000,
|
|
103
|
+
isotropic: bool = True,
|
|
104
|
+
nonnegativity: bool = False,
|
|
105
|
+
lipschitz_const: float = 8.0,
|
|
106
|
+
gpu_id: int = 0,
|
|
107
|
+
half_precision: bool = False,
|
|
100
108
|
) -> cp.ndarray:
|
|
101
109
|
"""
|
|
102
110
|
Primal Dual algorithm for non-smooth convex Total Variation functional :cite:`chan1999nonlinear`. See more in :ref:`method_total_variation_PD`.
|
|
@@ -117,6 +125,8 @@ def total_variation_PD(
|
|
|
117
125
|
Lipschitz constant to control convergence. Defaults to 8.
|
|
118
126
|
gpu_id : int
|
|
119
127
|
GPU device index to perform processing on. Defaults to 0.
|
|
128
|
+
half_precision : bool
|
|
129
|
+
Perform faster computation in half-precision with a very minimal sacrifice in quality. Defaults to False.
|
|
120
130
|
|
|
121
131
|
Returns
|
|
122
132
|
-------
|
|
@@ -139,7 +149,7 @@ def total_variation_PD(
|
|
|
139
149
|
if nonnegativity:
|
|
140
150
|
nonneg = 1
|
|
141
151
|
|
|
142
|
-
return
|
|
152
|
+
return PD_TV_cupy(
|
|
143
153
|
data,
|
|
144
154
|
regularisation_parameter,
|
|
145
155
|
iterations,
|
|
@@ -147,4 +157,5 @@ def total_variation_PD(
|
|
|
147
157
|
nonneg,
|
|
148
158
|
lipschitz_const,
|
|
149
159
|
gpu_id,
|
|
160
|
+
half_precision,
|
|
150
161
|
)
|
httomolibgpu/misc/supp_func.py
CHANGED
|
@@ -159,7 +159,7 @@ def data_checker(
|
|
|
159
159
|
data: cp.ndarray,
|
|
160
160
|
verbosity: bool = True,
|
|
161
161
|
method_name: Optional[str] = None,
|
|
162
|
-
) ->
|
|
162
|
+
) -> cp.ndarray:
|
|
163
163
|
"""
|
|
164
164
|
Function that performs the variety of checks on input data, in some cases also correct the data and prints warnings.
|
|
165
165
|
Currently it checks for: the presence of infs and nans in data.
|
httomolibgpu/prep/phase.py
CHANGED
|
@@ -29,10 +29,8 @@ cupy_run = cupywrapper.cupy_run
|
|
|
29
29
|
from unittest.mock import Mock
|
|
30
30
|
|
|
31
31
|
if cupy_run:
|
|
32
|
-
from httomolibgpu.cuda_kernels import load_cuda_module
|
|
33
32
|
from cupyx.scipy.fft import fft2, ifft2, fftshift
|
|
34
33
|
else:
|
|
35
|
-
load_cuda_module = Mock()
|
|
36
34
|
fft2 = Mock()
|
|
37
35
|
ifft2 = Mock()
|
|
38
36
|
fftshift = Mock()
|
|
@@ -44,225 +42,10 @@ import math
|
|
|
44
42
|
from httomolibgpu.misc.supp_func import data_checker
|
|
45
43
|
|
|
46
44
|
__all__ = [
|
|
47
|
-
"paganin_filter_savu",
|
|
48
45
|
"paganin_filter_tomopy",
|
|
49
46
|
]
|
|
50
47
|
|
|
51
48
|
|
|
52
|
-
## %%%%%%%%%%%%%%%%%%%%%%% paganin_filter %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ##
|
|
53
|
-
#: CuPy implementation of Paganin filter from Savu
|
|
54
|
-
def paganin_filter_savu(
|
|
55
|
-
data: cp.ndarray,
|
|
56
|
-
ratio: float = 250.0,
|
|
57
|
-
energy: float = 53.0,
|
|
58
|
-
distance: float = 1.0,
|
|
59
|
-
resolution: float = 1.28,
|
|
60
|
-
pad_y: int = 100,
|
|
61
|
-
pad_x: int = 100,
|
|
62
|
-
pad_method: str = "edge",
|
|
63
|
-
increment: float = 0.0,
|
|
64
|
-
) -> cp.ndarray:
|
|
65
|
-
"""
|
|
66
|
-
Apply Paganin filter (for denoising or contrast enhancement) to
|
|
67
|
-
projections.
|
|
68
|
-
|
|
69
|
-
Parameters
|
|
70
|
-
----------
|
|
71
|
-
data : cp.ndarray
|
|
72
|
-
The stack of projections to filter.
|
|
73
|
-
|
|
74
|
-
ratio : float, optional
|
|
75
|
-
Ratio of delta/beta.
|
|
76
|
-
|
|
77
|
-
energy : float, optional
|
|
78
|
-
Beam energy in keV.
|
|
79
|
-
|
|
80
|
-
distance : float, optional
|
|
81
|
-
Distance from sample to detector in metres.
|
|
82
|
-
|
|
83
|
-
resolution : float, optional
|
|
84
|
-
Pixel size in microns.
|
|
85
|
-
|
|
86
|
-
pad_y : int, optional
|
|
87
|
-
Pad the top and bottom of projections.
|
|
88
|
-
|
|
89
|
-
pad_x : int, optional
|
|
90
|
-
Pad the left and right of projections.
|
|
91
|
-
|
|
92
|
-
pad_method : str, optional
|
|
93
|
-
Numpy pad method to use.
|
|
94
|
-
|
|
95
|
-
increment : float, optional
|
|
96
|
-
Increment all values by this amount before taking the log.
|
|
97
|
-
|
|
98
|
-
Returns
|
|
99
|
-
-------
|
|
100
|
-
cp.ndarray
|
|
101
|
-
The stack of filtered projections.
|
|
102
|
-
"""
|
|
103
|
-
# Check the input data is valid
|
|
104
|
-
if data.ndim != 3:
|
|
105
|
-
raise ValueError(
|
|
106
|
-
f"Invalid number of dimensions in data: {data.ndim},"
|
|
107
|
-
" please provide a stack of 2D projections."
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
data = data_checker(data, verbosity=True, method_name="paganin_filter_savu")
|
|
111
|
-
|
|
112
|
-
# Setup various values for the filter
|
|
113
|
-
_, height, width = data.shape
|
|
114
|
-
micron = 1e-6
|
|
115
|
-
keV = 1000.0
|
|
116
|
-
energy *= keV
|
|
117
|
-
resolution *= micron
|
|
118
|
-
wavelength = (1240.0 / energy) * 1e-9
|
|
119
|
-
|
|
120
|
-
height1 = height + 2 * pad_y
|
|
121
|
-
width1 = width + 2 * pad_x
|
|
122
|
-
|
|
123
|
-
# Define the paganin filter, taking into account the padding that will be
|
|
124
|
-
# applied to the projections (if any)
|
|
125
|
-
|
|
126
|
-
# Using raw kernel her as indexing is direct and it avoids a lot of temporaries
|
|
127
|
-
# and tiny kernels
|
|
128
|
-
module = load_cuda_module("paganin_filter_gen")
|
|
129
|
-
kernel = module.get_function("paganin_filter_gen")
|
|
130
|
-
|
|
131
|
-
# Apply padding to all the 2D projections
|
|
132
|
-
# Note: this takes considerable time on GPU...
|
|
133
|
-
data = cp.pad(data, ((0, 0), (pad_y, pad_y), (pad_x, pad_x)), mode=pad_method)
|
|
134
|
-
|
|
135
|
-
precond_kernel_float = cp.ElementwiseKernel(
|
|
136
|
-
"T data",
|
|
137
|
-
"T out",
|
|
138
|
-
"""
|
|
139
|
-
if (isnan(data)) {
|
|
140
|
-
out = T(0);
|
|
141
|
-
} else if (isinf(data)) {
|
|
142
|
-
out = data < 0.0 ? -3.402823e38f : 3.402823e38f; // FLT_MAX, not available in cupy
|
|
143
|
-
} else if (data == 0.0) {
|
|
144
|
-
out = 1.0;
|
|
145
|
-
} else {
|
|
146
|
-
out = data;
|
|
147
|
-
}
|
|
148
|
-
""",
|
|
149
|
-
name="paganin_precond_float",
|
|
150
|
-
no_return=True,
|
|
151
|
-
)
|
|
152
|
-
precond_kernel_int = cp.ElementwiseKernel(
|
|
153
|
-
"T data",
|
|
154
|
-
"T out",
|
|
155
|
-
"""out = data == 0 ? 1 : data""",
|
|
156
|
-
name="paganin_precond_int",
|
|
157
|
-
no_return=True,
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
if data.dtype in (cp.float32, cp.float64):
|
|
161
|
-
precond_kernel_float(data, data)
|
|
162
|
-
else:
|
|
163
|
-
precond_kernel_int(data, data)
|
|
164
|
-
|
|
165
|
-
# avoid normalising in both directions - we include multiplier in the post_kernel
|
|
166
|
-
data = cp.asarray(data, dtype=cp.complex64)
|
|
167
|
-
data = fft2(data, axes=(-2, -1), overwrite_x=True, norm="backward")
|
|
168
|
-
|
|
169
|
-
# prepare filter here, while the GPU is busy with the FFT
|
|
170
|
-
filtercomplex = cp.empty((height1, width1), dtype=cp.complex64)
|
|
171
|
-
bx = 16
|
|
172
|
-
by = 8
|
|
173
|
-
gx = (width1 + bx - 1) // bx
|
|
174
|
-
gy = (height1 + by - 1) // by
|
|
175
|
-
kernel(
|
|
176
|
-
grid=(gx, gy, 1),
|
|
177
|
-
block=(bx, by, 1),
|
|
178
|
-
args=(
|
|
179
|
-
cp.int32(width1),
|
|
180
|
-
cp.int32(height1),
|
|
181
|
-
cp.float32(resolution),
|
|
182
|
-
cp.float32(wavelength),
|
|
183
|
-
cp.float32(distance),
|
|
184
|
-
cp.float32(ratio),
|
|
185
|
-
filtercomplex,
|
|
186
|
-
),
|
|
187
|
-
)
|
|
188
|
-
data *= filtercomplex
|
|
189
|
-
|
|
190
|
-
data = ifft2(data, axes=(-2, -1), overwrite_x=True, norm="forward")
|
|
191
|
-
|
|
192
|
-
post_kernel = cp.ElementwiseKernel(
|
|
193
|
-
"C pci1, raw float32 increment, raw float32 ratio, raw float32 fft_scale",
|
|
194
|
-
"T out",
|
|
195
|
-
"out = -0.5 * ratio * log(abs(pci1) * fft_scale + increment)",
|
|
196
|
-
name="paganin_post_proc",
|
|
197
|
-
no_return=True,
|
|
198
|
-
)
|
|
199
|
-
fft_scale = 1.0 / (data.shape[1] * data.shape[2])
|
|
200
|
-
res = cp.empty((data.shape[0], height, width), dtype=cp.float32)
|
|
201
|
-
post_kernel(
|
|
202
|
-
data[:, pad_y : pad_y + height, pad_x : pad_x + width],
|
|
203
|
-
np.float32(increment),
|
|
204
|
-
np.float32(ratio),
|
|
205
|
-
np.float32(fft_scale),
|
|
206
|
-
res,
|
|
207
|
-
)
|
|
208
|
-
return res
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
def _wavelength(energy: float) -> float:
|
|
212
|
-
SPEED_OF_LIGHT = 299792458e2 # [cm/s]
|
|
213
|
-
PLANCK_CONSTANT = 6.58211928e-19 # [keV*s]
|
|
214
|
-
return 2 * math.pi * PLANCK_CONSTANT * SPEED_OF_LIGHT / energy
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
def _reciprocal_grid(pixel_size: float, shape_proj: tuple) -> cp.ndarray:
|
|
218
|
-
"""
|
|
219
|
-
Calculate reciprocal grid.
|
|
220
|
-
|
|
221
|
-
Parameters
|
|
222
|
-
----------
|
|
223
|
-
pixel_size : float
|
|
224
|
-
Detector pixel size in cm.
|
|
225
|
-
shape_proj : tuple
|
|
226
|
-
Shape of the reciprocal grid along x and y axes.
|
|
227
|
-
|
|
228
|
-
Returns
|
|
229
|
-
-------
|
|
230
|
-
ndarray
|
|
231
|
-
Grid coordinates.
|
|
232
|
-
"""
|
|
233
|
-
# Sampling in reciprocal space.
|
|
234
|
-
indx = _reciprocal_coord(pixel_size, shape_proj[0])
|
|
235
|
-
indy = _reciprocal_coord(pixel_size, shape_proj[1])
|
|
236
|
-
indx_sq = cp.square(indx)
|
|
237
|
-
indy_sq = cp.square(indy)
|
|
238
|
-
|
|
239
|
-
return cp.add.outer(indx_sq, indy_sq)
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
def _reciprocal_coord(pixel_size: float, num_grid: int) -> cp.ndarray:
|
|
243
|
-
"""
|
|
244
|
-
Calculate reciprocal grid coordinates for a given pixel size
|
|
245
|
-
and discretization.
|
|
246
|
-
|
|
247
|
-
Parameters
|
|
248
|
-
----------
|
|
249
|
-
pixel_size : float
|
|
250
|
-
Detector pixel size in cm.
|
|
251
|
-
num_grid : int
|
|
252
|
-
Size of the reciprocal grid.
|
|
253
|
-
|
|
254
|
-
Returns
|
|
255
|
-
-------
|
|
256
|
-
ndarray
|
|
257
|
-
Grid coordinates.
|
|
258
|
-
"""
|
|
259
|
-
n = num_grid - 1
|
|
260
|
-
rc = cp.arange(-n, num_grid, 2, dtype=cp.float32)
|
|
261
|
-
rc *= 2 * math.pi / (n * pixel_size)
|
|
262
|
-
return rc
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
##-------------------------------------------------------------##
|
|
266
49
|
##-------------------------------------------------------------##
|
|
267
50
|
# Adaptation of retrieve_phase (Paganin filter) from TomoPy
|
|
268
51
|
def paganin_filter_tomopy(
|
|
@@ -287,7 +70,7 @@ def paganin_filter_tomopy(
|
|
|
287
70
|
energy : float, optional
|
|
288
71
|
Energy of incident wave in keV.
|
|
289
72
|
alpha : float, optional
|
|
290
|
-
Regularization parameter, the ratio of delta/beta.
|
|
73
|
+
Regularization parameter, the ratio of delta/beta. Smaller values lead to less noise and more blur.
|
|
291
74
|
|
|
292
75
|
Returns
|
|
293
76
|
-------
|
|
@@ -412,3 +195,57 @@ def _pad_projections_to_second_power(
|
|
|
412
195
|
def _paganin_filter_factor2(energy, dist, alpha, w2):
|
|
413
196
|
# Alpha represents the ratio of delta/beta.
|
|
414
197
|
return 1 / (_wavelength(energy) * dist * w2 / (4 * math.pi) + alpha)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _wavelength(energy: float) -> float:
|
|
201
|
+
SPEED_OF_LIGHT = 299792458e2 # [cm/s]
|
|
202
|
+
PLANCK_CONSTANT = 6.58211928e-19 # [keV*s]
|
|
203
|
+
return 2 * math.pi * PLANCK_CONSTANT * SPEED_OF_LIGHT / energy
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _reciprocal_grid(pixel_size: float, shape_proj: tuple) -> cp.ndarray:
|
|
207
|
+
"""
|
|
208
|
+
Calculate reciprocal grid.
|
|
209
|
+
|
|
210
|
+
Parameters
|
|
211
|
+
----------
|
|
212
|
+
pixel_size : float
|
|
213
|
+
Detector pixel size in cm.
|
|
214
|
+
shape_proj : tuple
|
|
215
|
+
Shape of the reciprocal grid along x and y axes.
|
|
216
|
+
|
|
217
|
+
Returns
|
|
218
|
+
-------
|
|
219
|
+
ndarray
|
|
220
|
+
Grid coordinates.
|
|
221
|
+
"""
|
|
222
|
+
# Sampling in reciprocal space.
|
|
223
|
+
indx = _reciprocal_coord(pixel_size, shape_proj[0])
|
|
224
|
+
indy = _reciprocal_coord(pixel_size, shape_proj[1])
|
|
225
|
+
indx_sq = cp.square(indx)
|
|
226
|
+
indy_sq = cp.square(indy)
|
|
227
|
+
|
|
228
|
+
return cp.add.outer(indx_sq, indy_sq)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _reciprocal_coord(pixel_size: float, num_grid: int) -> cp.ndarray:
|
|
232
|
+
"""
|
|
233
|
+
Calculate reciprocal grid coordinates for a given pixel size
|
|
234
|
+
and discretization.
|
|
235
|
+
|
|
236
|
+
Parameters
|
|
237
|
+
----------
|
|
238
|
+
pixel_size : float
|
|
239
|
+
Detector pixel size in cm.
|
|
240
|
+
num_grid : int
|
|
241
|
+
Size of the reciprocal grid.
|
|
242
|
+
|
|
243
|
+
Returns
|
|
244
|
+
-------
|
|
245
|
+
ndarray
|
|
246
|
+
Grid coordinates.
|
|
247
|
+
"""
|
|
248
|
+
n = num_grid - 1
|
|
249
|
+
rc = cp.arange(-n, num_grid, 2, dtype=cp.float32)
|
|
250
|
+
rc *= 2 * math.pi / (n * pixel_size)
|
|
251
|
+
return rc
|
httomolibgpu/prep/stripe.py
CHANGED
|
@@ -143,8 +143,8 @@ def remove_stripe_ti(
|
|
|
143
143
|
|
|
144
144
|
_, _, dx_orig = data.shape
|
|
145
145
|
if (dx_orig % 2) != 0:
|
|
146
|
-
# the horizontal detector size is odd, data needs to be padded
|
|
147
|
-
|
|
146
|
+
# if the horizontal detector size is odd, the data needs to be padded
|
|
147
|
+
data = cp.pad(data, ((0, 0), (0, 0), (0, 1)), mode="edge")
|
|
148
148
|
|
|
149
149
|
gamma = beta * ((1 - beta) / (1 + beta)) ** cp.abs(
|
|
150
150
|
cp.fft.fftfreq(data.shape[-1]) * data.shape[-1]
|
|
@@ -154,7 +154,11 @@ def remove_stripe_ti(
|
|
|
154
154
|
v = v - v[:, 0:1]
|
|
155
155
|
v = cp.fft.irfft(cp.fft.rfft(v) * cp.fft.rfft(gamma)).astype(data.dtype)
|
|
156
156
|
data[:] += v
|
|
157
|
-
|
|
157
|
+
if (dx_orig % 2) != 0:
|
|
158
|
+
# unpad
|
|
159
|
+
return data[:, :, :-1]
|
|
160
|
+
else:
|
|
161
|
+
return data
|
|
158
162
|
|
|
159
163
|
|
|
160
164
|
######## Optimized version for Vo-all ring removal in tomopy########
|
httomolibgpu/recon/algorithm.py
CHANGED
|
@@ -37,8 +37,8 @@ else:
|
|
|
37
37
|
RecToolsDIRCuPy = Mock()
|
|
38
38
|
RecToolsIRCuPy = Mock()
|
|
39
39
|
|
|
40
|
-
from numpy import float32
|
|
41
|
-
from typing import Optional, Type
|
|
40
|
+
from numpy import float32
|
|
41
|
+
from typing import Optional, Type, Union
|
|
42
42
|
|
|
43
43
|
from httomolibgpu.misc.supp_func import data_checker
|
|
44
44
|
|
|
@@ -49,6 +49,7 @@ __all__ = [
|
|
|
49
49
|
"LPRec3d_tomobar",
|
|
50
50
|
"SIRT3d_tomobar",
|
|
51
51
|
"CGLS3d_tomobar",
|
|
52
|
+
"FISTA3d_tomobar",
|
|
52
53
|
]
|
|
53
54
|
|
|
54
55
|
input_data_axis_labels = ["angles", "detY", "detX"] # set the labels of the input data
|
|
@@ -59,7 +60,7 @@ def FBP2d_astra(
|
|
|
59
60
|
data: np.ndarray,
|
|
60
61
|
angles: np.ndarray,
|
|
61
62
|
center: Optional[float] = None,
|
|
62
|
-
detector_pad: int =
|
|
63
|
+
detector_pad: Union[bool, int] = False,
|
|
63
64
|
filter_type: str = "ram-lak",
|
|
64
65
|
filter_parameter: Optional[float] = None,
|
|
65
66
|
filter_d: Optional[float] = None,
|
|
@@ -81,8 +82,9 @@ def FBP2d_astra(
|
|
|
81
82
|
An array of angles given in radians.
|
|
82
83
|
center : float, optional
|
|
83
84
|
The center of rotation (CoR).
|
|
84
|
-
detector_pad : int
|
|
85
|
-
Detector width padding with edge values to remove circle/arc type artifacts in the reconstruction.
|
|
85
|
+
detector_pad : bool, int
|
|
86
|
+
Detector width padding with edge values to remove circle/arc type artifacts in the reconstruction. Set to True to perform
|
|
87
|
+
an automated padding or specify a certain value as an integer.
|
|
86
88
|
filter_type: str
|
|
87
89
|
Type of projection filter, see ASTRA's API for all available options for filters.
|
|
88
90
|
filter_parameter: float, optional
|
|
@@ -95,7 +97,7 @@ def FBP2d_astra(
|
|
|
95
97
|
recon_mask_radius: float
|
|
96
98
|
The radius of the circular mask that applies to the reconstructed slice in order to crop
|
|
97
99
|
out some undesirable artifacts. The values outside the given diameter will be set to zero.
|
|
98
|
-
|
|
100
|
+
To implement the cropping one can use the range [0.7-1.0] or set to 2.0 when no cropping required.
|
|
99
101
|
neglog: bool
|
|
100
102
|
Take negative logarithm on input data to convert to attenuation coefficient or a density of the scanned object. Defaults to False,
|
|
101
103
|
assuming that the negative log is taken either in normalisation procedure on with Paganin filter application.
|
|
@@ -119,7 +121,7 @@ def FBP2d_astra(
|
|
|
119
121
|
|
|
120
122
|
detY_size = data_shape[1]
|
|
121
123
|
reconstruction = np.empty(
|
|
122
|
-
(recon_size, detY_size, recon_size), dtype=
|
|
124
|
+
(recon_size, detY_size, recon_size), dtype=float32, order="C"
|
|
123
125
|
)
|
|
124
126
|
_take_neg_log_np(data) if neglog else data
|
|
125
127
|
|
|
@@ -142,7 +144,7 @@ def FBP3d_tomobar(
|
|
|
142
144
|
data: cp.ndarray,
|
|
143
145
|
angles: np.ndarray,
|
|
144
146
|
center: Optional[float] = None,
|
|
145
|
-
detector_pad: int =
|
|
147
|
+
detector_pad: Union[bool, int] = False,
|
|
146
148
|
filter_freq_cutoff: float = 0.35,
|
|
147
149
|
recon_size: Optional[int] = None,
|
|
148
150
|
recon_mask_radius: Optional[float] = 0.95,
|
|
@@ -152,7 +154,7 @@ def FBP3d_tomobar(
|
|
|
152
154
|
"""
|
|
153
155
|
Perform Filtered Backprojection (FBP) reconstruction using ASTRA toolbox :cite:`van2016fast` and
|
|
154
156
|
ToMoBAR :cite:`kazantsev2020tomographic` wrappers.
|
|
155
|
-
This is a 3D recon from the CuPy array directly and using a custom built SINC filter for filtration in Fourier space,
|
|
157
|
+
This is a 3D recon from the CuPy array directly and using a custom built SINC filter for filtration in Fourier space,
|
|
156
158
|
see more in :ref:`method_FBP3d_tomobar`.
|
|
157
159
|
|
|
158
160
|
Parameters
|
|
@@ -163,17 +165,18 @@ def FBP3d_tomobar(
|
|
|
163
165
|
An array of angles given in radians.
|
|
164
166
|
center : float, optional
|
|
165
167
|
The center of rotation (CoR).
|
|
166
|
-
detector_pad : int
|
|
167
|
-
Detector width padding with edge values to remove circle/arc type artifacts in the reconstruction.
|
|
168
|
+
detector_pad : bool, int
|
|
169
|
+
Detector width padding with edge values to remove circle/arc type artifacts in the reconstruction. Set to True to perform
|
|
170
|
+
an automated padding or specify a certain value as an integer.
|
|
168
171
|
filter_freq_cutoff : float
|
|
169
|
-
Cutoff frequency parameter for the SINC filter, the lower values may produce better contrast but noisy reconstruction. The filter change will also affect the dynamic range of the reconstructed image.
|
|
172
|
+
Cutoff frequency parameter for the SINC filter, the lower values may produce better contrast but noisy reconstruction. The filter change will also affect the dynamic range of the reconstructed image.
|
|
170
173
|
recon_size : int, optional
|
|
171
174
|
The [recon_size, recon_size] shape of the reconstructed slice in pixels.
|
|
172
175
|
By default (None), the reconstructed size will be the dimension of the horizontal detector.
|
|
173
176
|
recon_mask_radius: float, optional
|
|
174
177
|
The radius of the circular mask that applies to the reconstructed slice in order to crop
|
|
175
178
|
out some undesirable artifacts. The values outside the given diameter will be set to zero.
|
|
176
|
-
|
|
179
|
+
To implement the cropping one can use the range [0.7-1.0] or set to 2.0 when no cropping required.
|
|
177
180
|
neglog: bool
|
|
178
181
|
Take negative logarithm on input data to convert to attenuation coefficient or a density of the scanned object. Defaults to False,
|
|
179
182
|
assuming that the negative log is taken either in normalisation procedure on with Paganin filter application.
|
|
@@ -206,11 +209,14 @@ def LPRec3d_tomobar(
|
|
|
206
209
|
data: cp.ndarray,
|
|
207
210
|
angles: np.ndarray,
|
|
208
211
|
center: Optional[float] = None,
|
|
209
|
-
detector_pad: int =
|
|
212
|
+
detector_pad: Union[bool, int] = False,
|
|
210
213
|
filter_type: str = "shepp",
|
|
211
214
|
filter_freq_cutoff: float = 1.0,
|
|
212
215
|
recon_size: Optional[int] = None,
|
|
213
|
-
recon_mask_radius:
|
|
216
|
+
recon_mask_radius: float = 0.95,
|
|
217
|
+
power_of_2_oversampling: Optional[bool] = True,
|
|
218
|
+
min_mem_usage_filter: Optional[bool] = False,
|
|
219
|
+
min_mem_usage_ifft2: Optional[bool] = False,
|
|
214
220
|
neglog: bool = False,
|
|
215
221
|
) -> cp.ndarray:
|
|
216
222
|
"""
|
|
@@ -226,8 +232,9 @@ def LPRec3d_tomobar(
|
|
|
226
232
|
An array of angles given in radians.
|
|
227
233
|
center : float, optional
|
|
228
234
|
The center of rotation (CoR).
|
|
229
|
-
detector_pad : int
|
|
230
|
-
Detector width padding with edge values to remove circle/arc type artifacts in the reconstruction.
|
|
235
|
+
detector_pad : bool, int
|
|
236
|
+
Detector width padding with edge values to remove circle/arc type artifacts in the reconstruction. Set to True to perform
|
|
237
|
+
an automated padding or specify a certain value as an integer.
|
|
231
238
|
filter_type : str
|
|
232
239
|
Filter type, the accepted strings are: none, ramp, shepp, cosine, cosine2, hamming, hann, parzen.
|
|
233
240
|
filter_freq_cutoff : float
|
|
@@ -235,10 +242,10 @@ def LPRec3d_tomobar(
|
|
|
235
242
|
recon_size : int, optional
|
|
236
243
|
The [recon_size, recon_size] shape of the reconstructed slice in pixels.
|
|
237
244
|
By default (None), the reconstructed size will be the dimension of the horizontal detector.
|
|
238
|
-
recon_mask_radius: float
|
|
245
|
+
recon_mask_radius: float
|
|
239
246
|
The radius of the circular mask that applies to the reconstructed slice in order to crop
|
|
240
247
|
out some undesirable artifacts. The values outside the given diameter will be set to zero.
|
|
241
|
-
|
|
248
|
+
To implement the cropping one can use the range [0.7-1.0] or set to 2.0 when no cropping required.
|
|
242
249
|
neglog: bool
|
|
243
250
|
Take negative logarithm on input data to convert to attenuation coefficient or a density of the scanned object. Defaults to False,
|
|
244
251
|
assuming that the negative log is taken either in normalisation procedure on with Paganin filter application.
|
|
@@ -261,6 +268,9 @@ def LPRec3d_tomobar(
|
|
|
261
268
|
data_axes_labels_order=input_data_axis_labels,
|
|
262
269
|
filter_type=filter_type,
|
|
263
270
|
cutoff_freq=filter_freq_cutoff,
|
|
271
|
+
power_of_2_oversampling=power_of_2_oversampling,
|
|
272
|
+
min_mem_usage_filter=min_mem_usage_filter,
|
|
273
|
+
min_mem_usage_ifft2=min_mem_usage_ifft2,
|
|
264
274
|
)
|
|
265
275
|
cp._default_memory_pool.free_all_blocks()
|
|
266
276
|
return cp.require(cp.swapaxes(reconstruction, 0, 1), requirements="C")
|
|
@@ -271,10 +281,11 @@ def SIRT3d_tomobar(
|
|
|
271
281
|
data: cp.ndarray,
|
|
272
282
|
angles: np.ndarray,
|
|
273
283
|
center: Optional[float] = None,
|
|
274
|
-
detector_pad: int =
|
|
284
|
+
detector_pad: Union[bool, int] = False,
|
|
275
285
|
recon_size: Optional[int] = None,
|
|
276
|
-
|
|
277
|
-
|
|
286
|
+
recon_mask_radius: float = 0.95,
|
|
287
|
+
iterations: int = 300,
|
|
288
|
+
nonnegativity: bool = True,
|
|
278
289
|
neglog: bool = False,
|
|
279
290
|
gpu_id: int = 0,
|
|
280
291
|
) -> cp.ndarray:
|
|
@@ -292,19 +303,24 @@ def SIRT3d_tomobar(
|
|
|
292
303
|
An array of angles given in radians.
|
|
293
304
|
center : float, optional
|
|
294
305
|
The center of rotation (CoR).
|
|
295
|
-
detector_pad : int
|
|
296
|
-
Detector width padding with edge values to remove circle/arc type artifacts in the reconstruction.
|
|
306
|
+
detector_pad : bool, int
|
|
307
|
+
Detector width padding with edge values to remove circle/arc type artifacts in the reconstruction. Set to True to perform
|
|
308
|
+
an automated padding or specify a certain value as an integer.
|
|
297
309
|
recon_size : int, optional
|
|
298
310
|
The [recon_size, recon_size] shape of the reconstructed slice in pixels.
|
|
299
311
|
By default (None), the reconstructed size will be the dimension of the horizontal detector.
|
|
300
|
-
|
|
312
|
+
recon_mask_radius: float
|
|
313
|
+
The radius of the circular mask that applies to the reconstructed slice in order to crop
|
|
314
|
+
out some undesirable artifacts. The values outside the given diameter will be set to zero.
|
|
315
|
+
To implement the cropping one can use the range [0.7-1.0] or set to 2.0 when no cropping required.
|
|
316
|
+
iterations : int
|
|
301
317
|
The number of SIRT iterations.
|
|
302
|
-
nonnegativity : bool
|
|
318
|
+
nonnegativity : bool
|
|
303
319
|
Impose nonnegativity constraint on reconstructed image.
|
|
304
320
|
neglog: bool
|
|
305
321
|
Take negative logarithm on input data to convert to attenuation coefficient or a density of the scanned object. Defaults to False,
|
|
306
322
|
assuming that the negative log is taken either in normalisation procedure on with Paganin filter application.
|
|
307
|
-
gpu_id : int
|
|
323
|
+
gpu_id : int
|
|
308
324
|
A GPU device index to perform operation on.
|
|
309
325
|
|
|
310
326
|
Returns
|
|
@@ -331,6 +347,7 @@ def SIRT3d_tomobar(
|
|
|
331
347
|
_algorithm_ = {
|
|
332
348
|
"iterations": iterations,
|
|
333
349
|
"nonnegativity": nonnegativity,
|
|
350
|
+
"recon_mask_radius": recon_mask_radius,
|
|
334
351
|
}
|
|
335
352
|
reconstruction = RecToolsCP.SIRT(_data_, _algorithm_)
|
|
336
353
|
cp._default_memory_pool.free_all_blocks()
|
|
@@ -342,10 +359,11 @@ def CGLS3d_tomobar(
|
|
|
342
359
|
data: cp.ndarray,
|
|
343
360
|
angles: np.ndarray,
|
|
344
361
|
center: Optional[float] = None,
|
|
345
|
-
detector_pad: int =
|
|
362
|
+
detector_pad: Union[bool, int] = False,
|
|
346
363
|
recon_size: Optional[int] = None,
|
|
347
|
-
|
|
348
|
-
|
|
364
|
+
recon_mask_radius: float = 0.95,
|
|
365
|
+
iterations: int = 20,
|
|
366
|
+
nonnegativity: bool = True,
|
|
349
367
|
neglog: bool = False,
|
|
350
368
|
gpu_id: int = 0,
|
|
351
369
|
) -> cp.ndarray:
|
|
@@ -363,14 +381,19 @@ def CGLS3d_tomobar(
|
|
|
363
381
|
An array of angles given in radians.
|
|
364
382
|
center : float, optional
|
|
365
383
|
The center of rotation (CoR).
|
|
366
|
-
detector_pad : int
|
|
367
|
-
Detector width padding with edge values to remove circle/arc type artifacts in the reconstruction.
|
|
384
|
+
detector_pad : bool, int
|
|
385
|
+
Detector width padding with edge values to remove circle/arc type artifacts in the reconstruction. Set to True to perform
|
|
386
|
+
an automated padding or specify a certain value as an integer.
|
|
368
387
|
recon_size : int, optional
|
|
369
388
|
The [recon_size, recon_size] shape of the reconstructed slice in pixels.
|
|
370
389
|
By default (None), the reconstructed size will be the dimension of the horizontal detector.
|
|
371
|
-
|
|
390
|
+
recon_mask_radius: float
|
|
391
|
+
The radius of the circular mask that applies to the reconstructed slice in order to crop
|
|
392
|
+
out some undesirable artifacts. The values outside the given diameter will be set to zero.
|
|
393
|
+
To implement the cropping one can use the range [0.7-1.0] or set to 2.0 when no cropping required.
|
|
394
|
+
iterations : int
|
|
372
395
|
The number of CGLS iterations.
|
|
373
|
-
nonnegativity : bool
|
|
396
|
+
nonnegativity : bool
|
|
374
397
|
Impose nonnegativity constraint on reconstructed image.
|
|
375
398
|
neglog: bool
|
|
376
399
|
Take negative logarithm on input data to convert to attenuation coefficient or a density of the scanned object. Defaults to False,
|
|
@@ -393,18 +416,119 @@ def CGLS3d_tomobar(
|
|
|
393
416
|
"projection_norm_data": _take_neg_log(data) if neglog else data,
|
|
394
417
|
"data_axes_labels_order": input_data_axis_labels,
|
|
395
418
|
} # data dictionary
|
|
396
|
-
_algorithm_ = {
|
|
419
|
+
_algorithm_ = {
|
|
420
|
+
"iterations": iterations,
|
|
421
|
+
"nonnegativity": nonnegativity,
|
|
422
|
+
"recon_mask_radius": recon_mask_radius,
|
|
423
|
+
}
|
|
397
424
|
reconstruction = RecToolsCP.CGLS(_data_, _algorithm_)
|
|
398
425
|
cp._default_memory_pool.free_all_blocks()
|
|
399
426
|
return cp.require(cp.swapaxes(reconstruction, 0, 1), requirements="C")
|
|
400
427
|
|
|
401
428
|
|
|
429
|
+
## %%%%%%%%%%%%%%%%%%%%%%% FISTA reconstruction %%%%%%%%%%%%%%%%%%%%%%%%%%%% ##
|
|
430
|
+
def FISTA3d_tomobar(
|
|
431
|
+
data: cp.ndarray,
|
|
432
|
+
angles: np.ndarray,
|
|
433
|
+
center: Optional[float] = None,
|
|
434
|
+
detector_pad: Union[bool, int] = False,
|
|
435
|
+
recon_size: Optional[int] = None,
|
|
436
|
+
recon_mask_radius: float = 0.95,
|
|
437
|
+
iterations: int = 20,
|
|
438
|
+
subsets_number: int = 6,
|
|
439
|
+
regularisation_type: str = "PD_TV",
|
|
440
|
+
regularisation_parameter: float = 0.000001,
|
|
441
|
+
regularisation_iterations: int = 50,
|
|
442
|
+
regularisation_half_precision: bool = True,
|
|
443
|
+
nonnegativity: bool = True,
|
|
444
|
+
neglog: bool = False,
|
|
445
|
+
gpu_id: int = 0,
|
|
446
|
+
) -> cp.ndarray:
|
|
447
|
+
"""
|
|
448
|
+
A Fast Iterative Shrinkage-Thresholding Algorithm :cite:`beck2009fast` with various types of regularisation or
|
|
449
|
+
denoising operations :cite:`kazantsev2019ccpi` (currently accepts ROF_TV and PD_TV regularisations only).
|
|
450
|
+
|
|
451
|
+
Parameters
|
|
452
|
+
----------
|
|
453
|
+
data : cp.ndarray
|
|
454
|
+
Projection data as a CuPy array.
|
|
455
|
+
angles : np.ndarray
|
|
456
|
+
An array of angles given in radians.
|
|
457
|
+
center : float, optional
|
|
458
|
+
The center of rotation (CoR).
|
|
459
|
+
detector_pad : bool, int
|
|
460
|
+
Detector width padding with edge values to remove circle/arc type artifacts in the reconstruction. Set to True to perform
|
|
461
|
+
an automated padding or specify a certain value as an integer.
|
|
462
|
+
recon_size : int, optional
|
|
463
|
+
The [recon_size, recon_size] shape of the reconstructed slice in pixels.
|
|
464
|
+
By default (None), the reconstructed size will be the dimension of the horizontal detector.
|
|
465
|
+
recon_mask_radius: float
|
|
466
|
+
The radius of the circular mask that applies to the reconstructed slice in order to crop
|
|
467
|
+
out some undesirable artifacts. The values outside the given diameter will be set to zero.
|
|
468
|
+
To implement the cropping one can use the range [0.7-1.0] or set to 2.0 when no cropping required.
|
|
469
|
+
iterations : int
|
|
470
|
+
The number of FISTA algorithm iterations.
|
|
471
|
+
subsets_number: int
|
|
472
|
+
The number of the ordered subsets to accelerate convergence. Keep the value bellow 10 to avoid divergence.
|
|
473
|
+
regularisation_type: str
|
|
474
|
+
A method to use for regularisation. Currently PD_TV and ROF_TV are available.
|
|
475
|
+
regularisation_parameter: float
|
|
476
|
+
The main regularisation parameter to control the amount of smoothing/noise removal. Larger values lead to stronger smoothing.
|
|
477
|
+
regularisation_iterations: int
|
|
478
|
+
The number of iterations for regularisers (aka INNER iterations).
|
|
479
|
+
regularisation_half_precision: bool
|
|
480
|
+
Perform faster regularisation computation in half-precision with a very minimal sacrifice in quality.
|
|
481
|
+
nonnegativity : bool
|
|
482
|
+
Impose nonnegativity constraint on the reconstructed image.
|
|
483
|
+
neglog: bool
|
|
484
|
+
Take negative logarithm on input data to convert to attenuation coefficient or a density of the scanned object. Defaults to False,
|
|
485
|
+
assuming that the negative log is taken either in normalisation procedure on with Paganin filter application.
|
|
486
|
+
gpu_id : int
|
|
487
|
+
A GPU device index to perform operation on.
|
|
488
|
+
|
|
489
|
+
Returns
|
|
490
|
+
-------
|
|
491
|
+
cp.ndarray
|
|
492
|
+
The FISTA reconstructed volume as a CuPy array.
|
|
493
|
+
"""
|
|
494
|
+
data = data_checker(data, verbosity=True, method_name="FISTA3d_tomobar")
|
|
495
|
+
|
|
496
|
+
RecToolsCP = _instantiate_iterative_recon_class(
|
|
497
|
+
data, angles, center, detector_pad, recon_size, gpu_id, datafidelity="LS"
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
_data_ = {
|
|
501
|
+
"projection_norm_data": _take_neg_log(data) if neglog else data,
|
|
502
|
+
"OS_number": subsets_number,
|
|
503
|
+
"data_axes_labels_order": input_data_axis_labels,
|
|
504
|
+
}
|
|
505
|
+
lc = RecToolsCP.powermethod(_data_) # calculate Lipschitz constant (run once)
|
|
506
|
+
|
|
507
|
+
_algorithm_ = {
|
|
508
|
+
"iterations": iterations,
|
|
509
|
+
"lipschitz_const": lc.get(),
|
|
510
|
+
"nonnegativity": nonnegativity,
|
|
511
|
+
"recon_mask_radius": recon_mask_radius,
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
_regularisation_ = {
|
|
515
|
+
"method": regularisation_type, # Selected regularisation method
|
|
516
|
+
"regul_param": regularisation_parameter, # Regularisation parameter
|
|
517
|
+
"iterations": regularisation_iterations, # The number of regularisation iterations
|
|
518
|
+
"half_precision": regularisation_half_precision, # enabling half-precision calculation
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
reconstruction = RecToolsCP.FISTA(_data_, _algorithm_, _regularisation_)
|
|
522
|
+
cp._default_memory_pool.free_all_blocks()
|
|
523
|
+
return cp.require(cp.swapaxes(reconstruction, 0, 1), requirements="C")
|
|
524
|
+
|
|
525
|
+
|
|
402
526
|
## %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ##
|
|
403
527
|
def _instantiate_direct_recon_class(
|
|
404
528
|
data: cp.ndarray,
|
|
405
529
|
angles: np.ndarray,
|
|
406
530
|
center: Optional[float] = None,
|
|
407
|
-
detector_pad: int =
|
|
531
|
+
detector_pad: Union[bool, int] = False,
|
|
408
532
|
recon_size: Optional[int] = None,
|
|
409
533
|
gpu_id: int = 0,
|
|
410
534
|
) -> Type:
|
|
@@ -414,7 +538,7 @@ def _instantiate_direct_recon_class(
|
|
|
414
538
|
data (cp.ndarray): data array
|
|
415
539
|
angles (np.ndarray): angles
|
|
416
540
|
center (Optional[float], optional): center of recon. Defaults to None.
|
|
417
|
-
detector_pad (int): Detector width padding. Defaults to
|
|
541
|
+
detector_pad : (Union[bool, int]) : Detector width padding. Defaults to False.
|
|
418
542
|
recon_size (Optional[int], optional): recon_size. Defaults to None.
|
|
419
543
|
gpu_id (int, optional): gpu ID. Defaults to 0.
|
|
420
544
|
|
|
@@ -425,6 +549,10 @@ def _instantiate_direct_recon_class(
|
|
|
425
549
|
center = data.shape[2] // 2 # making a crude guess
|
|
426
550
|
if recon_size is None:
|
|
427
551
|
recon_size = data.shape[2]
|
|
552
|
+
if detector_pad is True:
|
|
553
|
+
detector_pad = __estimate_detectorHoriz_padding(data.shape[2])
|
|
554
|
+
elif detector_pad is False:
|
|
555
|
+
detector_pad = 0
|
|
428
556
|
RecToolsCP = RecToolsDIRCuPy(
|
|
429
557
|
DetectorsDimH=data.shape[2], # Horizontal detector dimension
|
|
430
558
|
DetectorsDimH_pad=detector_pad, # padding for horizontal detector
|
|
@@ -444,7 +572,7 @@ def _instantiate_direct_recon2d_class(
|
|
|
444
572
|
data: np.ndarray,
|
|
445
573
|
angles: np.ndarray,
|
|
446
574
|
center: Optional[float] = None,
|
|
447
|
-
detector_pad: int =
|
|
575
|
+
detector_pad: Union[bool, int] = False,
|
|
448
576
|
recon_size: Optional[int] = None,
|
|
449
577
|
gpu_id: int = 0,
|
|
450
578
|
) -> Type:
|
|
@@ -454,7 +582,7 @@ def _instantiate_direct_recon2d_class(
|
|
|
454
582
|
data (cp.ndarray): data array
|
|
455
583
|
angles (np.ndarray): angles
|
|
456
584
|
center (Optional[float], optional): center of recon. Defaults to None.
|
|
457
|
-
detector_pad (int): Detector width padding. Defaults to
|
|
585
|
+
detector_pad : (Union[bool, int]) : Detector width padding. Defaults to False.
|
|
458
586
|
recon_size (Optional[int], optional): recon_size. Defaults to None.
|
|
459
587
|
gpu_id (int, optional): gpu ID. Defaults to 0.
|
|
460
588
|
|
|
@@ -465,6 +593,10 @@ def _instantiate_direct_recon2d_class(
|
|
|
465
593
|
center = data.shape[2] // 2 # making a crude guess
|
|
466
594
|
if recon_size is None:
|
|
467
595
|
recon_size = data.shape[2]
|
|
596
|
+
if detector_pad is True:
|
|
597
|
+
detector_pad = __estimate_detectorHoriz_padding(data.shape[2])
|
|
598
|
+
elif detector_pad is False:
|
|
599
|
+
detector_pad = 0
|
|
468
600
|
RecTools = RecToolsDIR(
|
|
469
601
|
DetectorsDimH=data.shape[2], # Horizontal detector dimension
|
|
470
602
|
DetectorsDimH_pad=detector_pad, # padding for horizontal detector
|
|
@@ -483,7 +615,7 @@ def _instantiate_iterative_recon_class(
|
|
|
483
615
|
data: cp.ndarray,
|
|
484
616
|
angles: np.ndarray,
|
|
485
617
|
center: Optional[float] = None,
|
|
486
|
-
detector_pad: int =
|
|
618
|
+
detector_pad: Union[bool, int] = False,
|
|
487
619
|
recon_size: Optional[int] = None,
|
|
488
620
|
gpu_id: int = 0,
|
|
489
621
|
datafidelity: str = "LS",
|
|
@@ -494,7 +626,7 @@ def _instantiate_iterative_recon_class(
|
|
|
494
626
|
data (cp.ndarray): data array
|
|
495
627
|
angles (np.ndarray): angles
|
|
496
628
|
center (Optional[float], optional): center of recon. Defaults to None.
|
|
497
|
-
detector_pad (int): Detector width padding. Defaults to
|
|
629
|
+
detector_pad : (Union[bool, int]) : Detector width padding. Defaults to False.
|
|
498
630
|
recon_size (Optional[int], optional): recon_size. Defaults to None.
|
|
499
631
|
datafidelity (str, optional): Data fidelity
|
|
500
632
|
gpu_id (int, optional): gpu ID. Defaults to 0.
|
|
@@ -506,6 +638,10 @@ def _instantiate_iterative_recon_class(
|
|
|
506
638
|
center = data.shape[2] // 2 # making a crude guess
|
|
507
639
|
if recon_size is None:
|
|
508
640
|
recon_size = data.shape[2]
|
|
641
|
+
if detector_pad is True:
|
|
642
|
+
detector_pad = __estimate_detectorHoriz_padding(data.shape[2])
|
|
643
|
+
elif detector_pad is False:
|
|
644
|
+
detector_pad = 0
|
|
509
645
|
RecToolsCP = RecToolsIRCuPy(
|
|
510
646
|
DetectorsDimH=data.shape[2], # Horizontal detector dimension
|
|
511
647
|
DetectorsDimH_pad=detector_pad, # padding for horizontal detector
|
|
@@ -537,3 +673,10 @@ def _take_neg_log_np(data: np.ndarray) -> np.ndarray:
|
|
|
537
673
|
data[np.isnan(data)] = 6.0
|
|
538
674
|
data[np.isinf(data)] = 0
|
|
539
675
|
return data
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
def __estimate_detectorHoriz_padding(detX_size) -> int:
|
|
679
|
+
det_half = detX_size // 2
|
|
680
|
+
padded_value_exact = int(np.sqrt(2 * (det_half**2))) - det_half
|
|
681
|
+
padded_add_margin = int(0.1 * padded_value_exact)
|
|
682
|
+
return padded_value_exact + padded_add_margin
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: httomolibgpu
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.1
|
|
4
4
|
Summary: Commonly used tomography data processing methods at DLS.
|
|
5
5
|
Author-email: Daniil Kazantsev <daniil.kazantsev@diamond.ac.uk>, Yousef Moazzam <yousef.moazzam@diamond.ac.uk>, Naman Gera <naman.gera@diamond.ac.uk>
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -19,7 +19,6 @@ Requires-Dist: scipy
|
|
|
19
19
|
Requires-Dist: pillow
|
|
20
20
|
Requires-Dist: scikit-image
|
|
21
21
|
Requires-Dist: tomobar
|
|
22
|
-
Requires-Dist: ccpi-regularisation-cupy
|
|
23
22
|
Provides-Extra: dev
|
|
24
23
|
Requires-Dist: pytest; extra == "dev"
|
|
25
24
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
@@ -1,29 +1,28 @@
|
|
|
1
|
-
httomolibgpu/__init__.py,sha256=
|
|
1
|
+
httomolibgpu/__init__.py,sha256=sz3ia5rSjC4lj6Xw4VZekh3OxmeVB2E2747bzyHqQdY,838
|
|
2
2
|
httomolibgpu/cupywrapper.py,sha256=6ITGJ2Jw5I5kVmKEL5LlsnLRniEqqBLsHiAjvLtk0Xk,493
|
|
3
3
|
httomolibgpu/cuda_kernels/__init__.py,sha256=VQNMaGcVDwiE-C64FfLtubHpLriLG0Y3_QnjHBSHrN0,884
|
|
4
4
|
httomolibgpu/cuda_kernels/calc_metrics.cu,sha256=oV7ZPcwjWafmZjbNsUkBYPvOViJ_nX3zBoOAuPCmIrA,11335
|
|
5
5
|
httomolibgpu/cuda_kernels/center_360_shifts.cu,sha256=Ya_8hxjXGtPBsPY3qfGJaugwnYrTFjFFretRcLiUfFQ,1631
|
|
6
6
|
httomolibgpu/cuda_kernels/generate_mask.cu,sha256=3il3r1J2cnTCd3UXO4GWGfBgGxj4pvrZnXviW_SXpO0,2650
|
|
7
7
|
httomolibgpu/cuda_kernels/median_kernel.cu,sha256=EECLUCoJkT9GQ9Db_FF6fYOG6cDSiAePTRZNxE4VZ68,1692
|
|
8
|
-
httomolibgpu/cuda_kernels/paganin_filter_gen.cu,sha256=REvnVqsg-Frev7S_SBi8jKVFHPwWlIxGfCV4NUJaO58,1099
|
|
9
8
|
httomolibgpu/cuda_kernels/raven_filter.cu,sha256=KX2TM_9tMpvoGCHezDNWYABCnv2cT9mlMo4IhxRUac0,1437
|
|
10
9
|
httomolibgpu/cuda_kernels/remove_nan_inf.cu,sha256=gv0ihkf6A_D_po9x7pmgFsQFhwZ1dB_HYc_0Tu-bpUU,630
|
|
11
10
|
httomolibgpu/misc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
11
|
httomolibgpu/misc/corr.py,sha256=1tUjwMku-MAPiLaH9IFe3zmF0p6rJFLruoObXSZelXY,4665
|
|
13
|
-
httomolibgpu/misc/denoise.py,sha256=
|
|
12
|
+
httomolibgpu/misc/denoise.py,sha256=l5FVdpur1I6YQcJJBfYTKjEsiDNyRYtpdOQZ7ZHicJw,4997
|
|
14
13
|
httomolibgpu/misc/morph.py,sha256=AlLk_kGFHF6vNrdICMpsXmTUDnCc7ey97-_DqwZb3Wc,7475
|
|
15
14
|
httomolibgpu/misc/rescale.py,sha256=K4VQ1AdxOAhe8tTSVb9VXVZsjBap5VlOtxHVdf9MU08,4416
|
|
16
|
-
httomolibgpu/misc/supp_func.py,sha256=
|
|
15
|
+
httomolibgpu/misc/supp_func.py,sha256=yDzNmRlIlIikQ4sKd2y9trQ9yQtblECmQ2JM5vmIY5I,6233
|
|
17
16
|
httomolibgpu/prep/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
17
|
httomolibgpu/prep/alignment.py,sha256=BuFTfLZD5_THQAKP_ikQ3fRE8JpN-JItGllZgrHRU5s,5657
|
|
19
18
|
httomolibgpu/prep/normalize.py,sha256=ozVUAs4UY2DY7MQtJKllUgahp_4wRFKPuc_3iQl6bCE,4879
|
|
20
|
-
httomolibgpu/prep/phase.py,sha256=
|
|
21
|
-
httomolibgpu/prep/stripe.py,sha256
|
|
19
|
+
httomolibgpu/prep/phase.py,sha256=zIuAVqlnHVqcDUBtj40NRBoHaO7O2KqGZ5CCUABRXBQ,7282
|
|
20
|
+
httomolibgpu/prep/stripe.py,sha256=YgOVb7Z5H7NFM3d2Y1jfNNwwj7ZMDv9nMZMMCvdBnVM,15150
|
|
22
21
|
httomolibgpu/recon/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
-
httomolibgpu/recon/algorithm.py,sha256=
|
|
22
|
+
httomolibgpu/recon/algorithm.py,sha256=EL0Y5xVkXR4tau5BYkEesekLxfSneIWmDdgEjfHDQ0o,27978
|
|
24
23
|
httomolibgpu/recon/rotation.py,sha256=k_E0lBRprJz6AGclagIkrzk_9dipADxPtL5BxrggSwM,27729
|
|
25
|
-
httomolibgpu-3.
|
|
26
|
-
httomolibgpu-3.
|
|
27
|
-
httomolibgpu-3.
|
|
28
|
-
httomolibgpu-3.
|
|
29
|
-
httomolibgpu-3.
|
|
24
|
+
httomolibgpu-3.1.dist-info/licenses/LICENSE,sha256=bXeLsgelPUUXw8HCIYiVC97Dpjhm2nB54m7TACdH8ng,48032
|
|
25
|
+
httomolibgpu-3.1.dist-info/METADATA,sha256=fVcG2CipC75a2sSwXNFl9OPxNLmZHTC24VDCcnhX7gI,3339
|
|
26
|
+
httomolibgpu-3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
27
|
+
httomolibgpu-3.1.dist-info/top_level.txt,sha256=nV0Ty_YvSPVd1O6MNWuIplD0w1nwk5hT76YgBZ-bzUw,13
|
|
28
|
+
httomolibgpu-3.1.dist-info/RECORD,,
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
#include <cupy/complex.cuh>
|
|
2
|
-
|
|
3
|
-
#ifndef M_PI
|
|
4
|
-
#define M_PI 3.1415926535897932384626433832795f
|
|
5
|
-
#endif
|
|
6
|
-
|
|
7
|
-
extern "C" __global__ void
|
|
8
|
-
paganin_filter_gen(int width1, int height1, float resolution, float wavelength,
|
|
9
|
-
float distance, float ratio, complex<float> *filtercomplex) {
|
|
10
|
-
int px = threadIdx.x + blockIdx.x * blockDim.x;
|
|
11
|
-
int py = threadIdx.y + blockIdx.y * blockDim.y;
|
|
12
|
-
if (px >= width1)
|
|
13
|
-
return;
|
|
14
|
-
if (py >= height1)
|
|
15
|
-
return;
|
|
16
|
-
|
|
17
|
-
float dpx = 1.0f / (width1 * resolution);
|
|
18
|
-
float dpy = 1.0f / (height1 * resolution);
|
|
19
|
-
int centerx = (width1 + 1) / 2 - 1;
|
|
20
|
-
int centery = (height1 + 1) / 2 - 1;
|
|
21
|
-
|
|
22
|
-
float pxx = (px - centerx) * dpx;
|
|
23
|
-
float pyy = (py - centery) * dpy;
|
|
24
|
-
float pd = (pxx * pxx + pyy * pyy) * wavelength * distance * M_PI;
|
|
25
|
-
;
|
|
26
|
-
float filter1 = 1.0f + ratio * pd;
|
|
27
|
-
|
|
28
|
-
complex<float> value = 1.0f / complex<float>(filter1, filter1);
|
|
29
|
-
|
|
30
|
-
// ifftshifting positions
|
|
31
|
-
int xshift = (width1 + 1) / 2;
|
|
32
|
-
int yshift = (height1 + 1) / 2;
|
|
33
|
-
int outX = (px + xshift) % width1;
|
|
34
|
-
int outY = (py + yshift) % height1;
|
|
35
|
-
|
|
36
|
-
filtercomplex[outY * width1 + outX] = value;
|
|
37
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|