httomolibgpu 2.7.1__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/corr.py +3 -3
- httomolibgpu/misc/denoise.py +30 -19
- httomolibgpu/misc/rescale.py +26 -42
- httomolibgpu/misc/supp_func.py +2 -2
- httomolibgpu/prep/phase.py +55 -218
- httomolibgpu/prep/stripe.py +7 -3
- httomolibgpu/recon/algorithm.py +199 -29
- {httomolibgpu-2.7.1.dist-info → httomolibgpu-3.1.dist-info}/METADATA +2 -3
- {httomolibgpu-2.7.1.dist-info → httomolibgpu-3.1.dist-info}/RECORD +13 -14
- httomolibgpu/cuda_kernels/paganin_filter_gen.cu +0 -37
- {httomolibgpu-2.7.1.dist-info → httomolibgpu-3.1.dist-info}/WHEEL +0 -0
- {httomolibgpu-2.7.1.dist-info → httomolibgpu-3.1.dist-info}/licenses/LICENSE +0 -0
- {httomolibgpu-2.7.1.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/corr.py
CHANGED
|
@@ -114,7 +114,7 @@ def median_filter(
|
|
|
114
114
|
|
|
115
115
|
|
|
116
116
|
def remove_outlier(
|
|
117
|
-
data: cp.ndarray, kernel_size: int = 3, dif: float =
|
|
117
|
+
data: cp.ndarray, kernel_size: int = 3, dif: float = 1000
|
|
118
118
|
) -> cp.ndarray:
|
|
119
119
|
"""Selectively applies 3D median filter to a 3D CuPy array to remove outliers. Also called a dezinger.
|
|
120
120
|
For more detailed information, see :ref:`method_outlier_removal`.
|
|
@@ -126,8 +126,8 @@ def remove_outlier(
|
|
|
126
126
|
kernel_size : int, optional
|
|
127
127
|
The size of the filter's kernel (a diameter).
|
|
128
128
|
dif : float, optional
|
|
129
|
-
Expected difference value between outlier value and the
|
|
130
|
-
median value of the
|
|
129
|
+
Expected difference value between the outlier value (central voxel) and the
|
|
130
|
+
median value of the neighbourhood. Lower values lead to median filtering.
|
|
131
131
|
|
|
132
132
|
Returns
|
|
133
133
|
-------
|
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/rescale.py
CHANGED
|
@@ -24,32 +24,32 @@ import numpy as np
|
|
|
24
24
|
from httomolibgpu import cupywrapper
|
|
25
25
|
|
|
26
26
|
cp = cupywrapper.cp
|
|
27
|
-
cupy_run = cupywrapper.cupy_run
|
|
28
27
|
|
|
29
28
|
from typing import Literal, Optional, Tuple, Union
|
|
30
29
|
|
|
31
30
|
from httomolibgpu.misc.supp_func import data_checker
|
|
32
31
|
|
|
32
|
+
|
|
33
33
|
__all__ = [
|
|
34
34
|
"rescale_to_int",
|
|
35
35
|
]
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
def rescale_to_int(
|
|
39
|
-
data:
|
|
39
|
+
data: cp.ndarray,
|
|
40
40
|
perc_range_min: float = 0.0,
|
|
41
41
|
perc_range_max: float = 100.0,
|
|
42
42
|
bits: Literal[8, 16, 32] = 8,
|
|
43
43
|
glob_stats: Optional[Tuple[float, float, float, int]] = None,
|
|
44
|
-
) ->
|
|
44
|
+
) -> cp.ndarray:
|
|
45
45
|
"""
|
|
46
46
|
Rescales the data given as float32 type and converts it into the range of an unsigned integer type
|
|
47
47
|
with the given number of bits. For more detailed information and examples, see :ref:`method_rescale_to_int`.
|
|
48
48
|
|
|
49
49
|
Parameters
|
|
50
50
|
----------
|
|
51
|
-
data :
|
|
52
|
-
Input data as a
|
|
51
|
+
data : cp.ndarray
|
|
52
|
+
Input data as a cupy array
|
|
53
53
|
perc_range_min: float, optional
|
|
54
54
|
The lower cutoff point in the input data, in percent of the data range (defaults to 0).
|
|
55
55
|
The lower bound is computed as min + perc_range_min/100*(max-min)
|
|
@@ -69,7 +69,7 @@ def rescale_to_int(
|
|
|
69
69
|
|
|
70
70
|
Returns
|
|
71
71
|
-------
|
|
72
|
-
|
|
72
|
+
cp.ndarray
|
|
73
73
|
The original data, clipped to the range specified with the perc_range_min and
|
|
74
74
|
perc_range_max, and scaled to the full range of the output integer type
|
|
75
75
|
"""
|
|
@@ -82,18 +82,13 @@ def rescale_to_int(
|
|
|
82
82
|
|
|
83
83
|
data = data_checker(data, verbosity=True, method_name="rescale_to_int")
|
|
84
84
|
|
|
85
|
-
if cupy_run:
|
|
86
|
-
xp = cp.get_array_module(data)
|
|
87
|
-
else:
|
|
88
|
-
import numpy as xp
|
|
89
|
-
|
|
90
85
|
# get the min and max integer values of the output type
|
|
91
|
-
output_min =
|
|
92
|
-
output_max =
|
|
86
|
+
output_min = cp.iinfo(output_dtype).min
|
|
87
|
+
output_max = cp.iinfo(output_dtype).max
|
|
93
88
|
|
|
94
89
|
if not isinstance(glob_stats, tuple):
|
|
95
|
-
min_value = float(
|
|
96
|
-
max_value = float(
|
|
90
|
+
min_value = float(cp.min(data))
|
|
91
|
+
max_value = float(cp.max(data))
|
|
97
92
|
else:
|
|
98
93
|
min_value = glob_stats[0]
|
|
99
94
|
max_value = glob_stats[1]
|
|
@@ -102,32 +97,21 @@ def rescale_to_int(
|
|
|
102
97
|
input_min = (perc_range_min * (range_intensity) / 100) + min_value
|
|
103
98
|
input_max = (perc_range_max * (range_intensity) / 100) + min_value
|
|
104
99
|
|
|
100
|
+
factor = cp.float32(1.0)
|
|
105
101
|
if (input_max - input_min) != 0.0:
|
|
106
|
-
factor =
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
rescale_kernel = cp.ElementwiseKernel(
|
|
122
|
-
"T x, raw T input_min, raw T input_max, raw T factor",
|
|
123
|
-
"O out",
|
|
124
|
-
"""
|
|
125
|
-
T x_clean = isnan(x) || isinf(x) ? T(0) : x;
|
|
126
|
-
T x_clipped = x_clean < input_min ? input_min : (x_clean > input_max ? input_max : x_clean);
|
|
127
|
-
T x_rebased = x_clipped - input_min;
|
|
128
|
-
out = O(x_rebased * factor);
|
|
129
|
-
""",
|
|
130
|
-
"rescale_to_int",
|
|
131
|
-
)
|
|
132
|
-
rescale_kernel(data, input_min, input_max, factor, res)
|
|
102
|
+
factor = cp.float32((output_max - output_min) / (input_max - input_min))
|
|
103
|
+
|
|
104
|
+
res = cp.empty(data.shape, dtype=output_dtype)
|
|
105
|
+
rescale_kernel = cp.ElementwiseKernel(
|
|
106
|
+
"T x, raw T input_min, raw T input_max, raw T factor",
|
|
107
|
+
"O out",
|
|
108
|
+
"""
|
|
109
|
+
T x_clean = isnan(x) || isinf(x) ? T(0) : x;
|
|
110
|
+
T x_clipped = x_clean < input_min ? input_min : (x_clean > input_max ? input_max : x_clean);
|
|
111
|
+
T x_rebased = x_clipped - input_min;
|
|
112
|
+
out = O(x_rebased * factor);
|
|
113
|
+
""",
|
|
114
|
+
"rescale_to_int",
|
|
115
|
+
)
|
|
116
|
+
rescale_kernel(data, input_min, input_max, factor, res)
|
|
133
117
|
return res
|
httomolibgpu/misc/supp_func.py
CHANGED
|
@@ -159,10 +159,10 @@ 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
|
-
Currently it checks for: the presence of infs and nans in data.
|
|
165
|
+
Currently it checks for: the presence of infs and nans in data.
|
|
166
166
|
|
|
167
167
|
Parameters
|
|
168
168
|
----------
|
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
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
# Created By : Tomography Team at DLS <scientificsoftware@diamond.ac.uk>
|
|
19
19
|
# Changes relative to ToMoBAR 2024.01 version
|
|
20
20
|
# ---------------------------------------------------------------------------
|
|
21
|
-
"""Module for tomographic reconstruction"""
|
|
21
|
+
"""Module for tomographic reconstruction. For more detailed information see :ref:`image_reconstruction_module`"""
|
|
22
22
|
|
|
23
23
|
import numpy as np
|
|
24
24
|
from httomolibgpu import cupywrapper
|
|
@@ -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,6 +60,7 @@ def FBP2d_astra(
|
|
|
59
60
|
data: np.ndarray,
|
|
60
61
|
angles: np.ndarray,
|
|
61
62
|
center: Optional[float] = None,
|
|
63
|
+
detector_pad: Union[bool, int] = False,
|
|
62
64
|
filter_type: str = "ram-lak",
|
|
63
65
|
filter_parameter: Optional[float] = None,
|
|
64
66
|
filter_d: Optional[float] = None,
|
|
@@ -70,8 +72,7 @@ def FBP2d_astra(
|
|
|
70
72
|
"""
|
|
71
73
|
Perform Filtered Backprojection (FBP) reconstruction slice-by-slice (2d) using ASTRA toolbox :cite:`van2016fast` and
|
|
72
74
|
ToMoBAR :cite:`kazantsev2020tomographic` wrappers.
|
|
73
|
-
This is a 2D recon using ASTRA's API for the
|
|
74
|
-
https://astra-toolbox.com/docs/algs/FBP_CUDA.html.
|
|
75
|
+
This is a 2D recon using ASTRA's API for the FBP_CUDA method, see more in :ref:`method_FBP2d_astra`.
|
|
75
76
|
|
|
76
77
|
Parameters
|
|
77
78
|
----------
|
|
@@ -81,6 +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).
|
|
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.
|
|
84
88
|
filter_type: str
|
|
85
89
|
Type of projection filter, see ASTRA's API for all available options for filters.
|
|
86
90
|
filter_parameter: float, optional
|
|
@@ -93,7 +97,7 @@ def FBP2d_astra(
|
|
|
93
97
|
recon_mask_radius: float
|
|
94
98
|
The radius of the circular mask that applies to the reconstructed slice in order to crop
|
|
95
99
|
out some undesirable artifacts. The values outside the given diameter will be set to zero.
|
|
96
|
-
|
|
100
|
+
To implement the cropping one can use the range [0.7-1.0] or set to 2.0 when no cropping required.
|
|
97
101
|
neglog: bool
|
|
98
102
|
Take negative logarithm on input data to convert to attenuation coefficient or a density of the scanned object. Defaults to False,
|
|
99
103
|
assuming that the negative log is taken either in normalisation procedure on with Paganin filter application.
|
|
@@ -112,12 +116,12 @@ def FBP2d_astra(
|
|
|
112
116
|
recon_size = data_shape[2]
|
|
113
117
|
|
|
114
118
|
RecTools = _instantiate_direct_recon2d_class(
|
|
115
|
-
data, angles, center, recon_size, gpu_id
|
|
119
|
+
data, angles, center, detector_pad, recon_size, gpu_id
|
|
116
120
|
)
|
|
117
121
|
|
|
118
122
|
detY_size = data_shape[1]
|
|
119
123
|
reconstruction = np.empty(
|
|
120
|
-
(recon_size, detY_size, recon_size), dtype=
|
|
124
|
+
(recon_size, detY_size, recon_size), dtype=float32, order="C"
|
|
121
125
|
)
|
|
122
126
|
_take_neg_log_np(data) if neglog else data
|
|
123
127
|
|
|
@@ -140,6 +144,7 @@ def FBP3d_tomobar(
|
|
|
140
144
|
data: cp.ndarray,
|
|
141
145
|
angles: np.ndarray,
|
|
142
146
|
center: Optional[float] = None,
|
|
147
|
+
detector_pad: Union[bool, int] = False,
|
|
143
148
|
filter_freq_cutoff: float = 0.35,
|
|
144
149
|
recon_size: Optional[int] = None,
|
|
145
150
|
recon_mask_radius: Optional[float] = 0.95,
|
|
@@ -149,7 +154,8 @@ def FBP3d_tomobar(
|
|
|
149
154
|
"""
|
|
150
155
|
Perform Filtered Backprojection (FBP) reconstruction using ASTRA toolbox :cite:`van2016fast` and
|
|
151
156
|
ToMoBAR :cite:`kazantsev2020tomographic` wrappers.
|
|
152
|
-
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,
|
|
158
|
+
see more in :ref:`method_FBP3d_tomobar`.
|
|
153
159
|
|
|
154
160
|
Parameters
|
|
155
161
|
----------
|
|
@@ -159,15 +165,18 @@ def FBP3d_tomobar(
|
|
|
159
165
|
An array of angles given in radians.
|
|
160
166
|
center : float, optional
|
|
161
167
|
The center of rotation (CoR).
|
|
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.
|
|
162
171
|
filter_freq_cutoff : float
|
|
163
|
-
Cutoff frequency parameter for the SINC filter, the lower values produce better contrast but noisy reconstruction.
|
|
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.
|
|
164
173
|
recon_size : int, optional
|
|
165
174
|
The [recon_size, recon_size] shape of the reconstructed slice in pixels.
|
|
166
175
|
By default (None), the reconstructed size will be the dimension of the horizontal detector.
|
|
167
176
|
recon_mask_radius: float, optional
|
|
168
177
|
The radius of the circular mask that applies to the reconstructed slice in order to crop
|
|
169
178
|
out some undesirable artifacts. The values outside the given diameter will be set to zero.
|
|
170
|
-
|
|
179
|
+
To implement the cropping one can use the range [0.7-1.0] or set to 2.0 when no cropping required.
|
|
171
180
|
neglog: bool
|
|
172
181
|
Take negative logarithm on input data to convert to attenuation coefficient or a density of the scanned object. Defaults to False,
|
|
173
182
|
assuming that the negative log is taken either in normalisation procedure on with Paganin filter application.
|
|
@@ -182,7 +191,7 @@ def FBP3d_tomobar(
|
|
|
182
191
|
data = data_checker(data, verbosity=True, method_name="FBP3d_tomobar")
|
|
183
192
|
|
|
184
193
|
RecToolsCP = _instantiate_direct_recon_class(
|
|
185
|
-
data, angles, center, recon_size, gpu_id
|
|
194
|
+
data, angles, center, detector_pad, recon_size, gpu_id
|
|
186
195
|
)
|
|
187
196
|
|
|
188
197
|
reconstruction = RecToolsCP.FBP(
|
|
@@ -200,16 +209,20 @@ def LPRec3d_tomobar(
|
|
|
200
209
|
data: cp.ndarray,
|
|
201
210
|
angles: np.ndarray,
|
|
202
211
|
center: Optional[float] = None,
|
|
212
|
+
detector_pad: Union[bool, int] = False,
|
|
203
213
|
filter_type: str = "shepp",
|
|
204
214
|
filter_freq_cutoff: float = 1.0,
|
|
205
215
|
recon_size: Optional[int] = None,
|
|
206
|
-
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,
|
|
207
220
|
neglog: bool = False,
|
|
208
221
|
) -> cp.ndarray:
|
|
209
222
|
"""
|
|
210
223
|
Fourier direct inversion in 3D on unequally spaced (also called as Log-Polar) grids using
|
|
211
224
|
CuPy array as an input. This implementation follows V. Nikitin's CUDA-C implementation and TomoCuPy package.
|
|
212
|
-
:cite:`andersson2016fast`.
|
|
225
|
+
:cite:`andersson2016fast`, see more in :ref:`method_LPRec3d_tomobar`.
|
|
213
226
|
|
|
214
227
|
Parameters
|
|
215
228
|
----------
|
|
@@ -219,17 +232,20 @@ def LPRec3d_tomobar(
|
|
|
219
232
|
An array of angles given in radians.
|
|
220
233
|
center : float, optional
|
|
221
234
|
The center of rotation (CoR).
|
|
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.
|
|
222
238
|
filter_type : str
|
|
223
239
|
Filter type, the accepted strings are: none, ramp, shepp, cosine, cosine2, hamming, hann, parzen.
|
|
224
240
|
filter_freq_cutoff : float
|
|
225
|
-
Cutoff frequency parameter for a filter.
|
|
241
|
+
Cutoff frequency parameter for a filter.
|
|
226
242
|
recon_size : int, optional
|
|
227
243
|
The [recon_size, recon_size] shape of the reconstructed slice in pixels.
|
|
228
244
|
By default (None), the reconstructed size will be the dimension of the horizontal detector.
|
|
229
|
-
recon_mask_radius: float
|
|
245
|
+
recon_mask_radius: float
|
|
230
246
|
The radius of the circular mask that applies to the reconstructed slice in order to crop
|
|
231
247
|
out some undesirable artifacts. The values outside the given diameter will be set to zero.
|
|
232
|
-
|
|
248
|
+
To implement the cropping one can use the range [0.7-1.0] or set to 2.0 when no cropping required.
|
|
233
249
|
neglog: bool
|
|
234
250
|
Take negative logarithm on input data to convert to attenuation coefficient or a density of the scanned object. Defaults to False,
|
|
235
251
|
assuming that the negative log is taken either in normalisation procedure on with Paganin filter application.
|
|
@@ -242,7 +258,9 @@ def LPRec3d_tomobar(
|
|
|
242
258
|
|
|
243
259
|
data = data_checker(data, verbosity=True, method_name="LPRec3d_tomobar")
|
|
244
260
|
|
|
245
|
-
RecToolsCP = _instantiate_direct_recon_class(
|
|
261
|
+
RecToolsCP = _instantiate_direct_recon_class(
|
|
262
|
+
data, angles, center, detector_pad, recon_size, 0
|
|
263
|
+
)
|
|
246
264
|
|
|
247
265
|
reconstruction = RecToolsCP.FOURIER_INV(
|
|
248
266
|
_take_neg_log(data) if neglog else data,
|
|
@@ -250,6 +268,9 @@ def LPRec3d_tomobar(
|
|
|
250
268
|
data_axes_labels_order=input_data_axis_labels,
|
|
251
269
|
filter_type=filter_type,
|
|
252
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,
|
|
253
274
|
)
|
|
254
275
|
cp._default_memory_pool.free_all_blocks()
|
|
255
276
|
return cp.require(cp.swapaxes(reconstruction, 0, 1), requirements="C")
|
|
@@ -260,9 +281,11 @@ def SIRT3d_tomobar(
|
|
|
260
281
|
data: cp.ndarray,
|
|
261
282
|
angles: np.ndarray,
|
|
262
283
|
center: Optional[float] = None,
|
|
284
|
+
detector_pad: Union[bool, int] = False,
|
|
263
285
|
recon_size: Optional[int] = None,
|
|
264
|
-
|
|
265
|
-
|
|
286
|
+
recon_mask_radius: float = 0.95,
|
|
287
|
+
iterations: int = 300,
|
|
288
|
+
nonnegativity: bool = True,
|
|
266
289
|
neglog: bool = False,
|
|
267
290
|
gpu_id: int = 0,
|
|
268
291
|
) -> cp.ndarray:
|
|
@@ -280,17 +303,24 @@ def SIRT3d_tomobar(
|
|
|
280
303
|
An array of angles given in radians.
|
|
281
304
|
center : float, optional
|
|
282
305
|
The center of rotation (CoR).
|
|
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.
|
|
283
309
|
recon_size : int, optional
|
|
284
310
|
The [recon_size, recon_size] shape of the reconstructed slice in pixels.
|
|
285
311
|
By default (None), the reconstructed size will be the dimension of the horizontal detector.
|
|
286
|
-
|
|
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
|
|
287
317
|
The number of SIRT iterations.
|
|
288
|
-
nonnegativity : bool
|
|
318
|
+
nonnegativity : bool
|
|
289
319
|
Impose nonnegativity constraint on reconstructed image.
|
|
290
320
|
neglog: bool
|
|
291
321
|
Take negative logarithm on input data to convert to attenuation coefficient or a density of the scanned object. Defaults to False,
|
|
292
322
|
assuming that the negative log is taken either in normalisation procedure on with Paganin filter application.
|
|
293
|
-
gpu_id : int
|
|
323
|
+
gpu_id : int
|
|
294
324
|
A GPU device index to perform operation on.
|
|
295
325
|
|
|
296
326
|
Returns
|
|
@@ -304,6 +334,7 @@ def SIRT3d_tomobar(
|
|
|
304
334
|
data,
|
|
305
335
|
angles,
|
|
306
336
|
center,
|
|
337
|
+
detector_pad,
|
|
307
338
|
recon_size,
|
|
308
339
|
gpu_id,
|
|
309
340
|
datafidelity="LS",
|
|
@@ -316,6 +347,7 @@ def SIRT3d_tomobar(
|
|
|
316
347
|
_algorithm_ = {
|
|
317
348
|
"iterations": iterations,
|
|
318
349
|
"nonnegativity": nonnegativity,
|
|
350
|
+
"recon_mask_radius": recon_mask_radius,
|
|
319
351
|
}
|
|
320
352
|
reconstruction = RecToolsCP.SIRT(_data_, _algorithm_)
|
|
321
353
|
cp._default_memory_pool.free_all_blocks()
|
|
@@ -327,9 +359,11 @@ def CGLS3d_tomobar(
|
|
|
327
359
|
data: cp.ndarray,
|
|
328
360
|
angles: np.ndarray,
|
|
329
361
|
center: Optional[float] = None,
|
|
362
|
+
detector_pad: Union[bool, int] = False,
|
|
330
363
|
recon_size: Optional[int] = None,
|
|
331
|
-
|
|
332
|
-
|
|
364
|
+
recon_mask_radius: float = 0.95,
|
|
365
|
+
iterations: int = 20,
|
|
366
|
+
nonnegativity: bool = True,
|
|
333
367
|
neglog: bool = False,
|
|
334
368
|
gpu_id: int = 0,
|
|
335
369
|
) -> cp.ndarray:
|
|
@@ -347,12 +381,19 @@ def CGLS3d_tomobar(
|
|
|
347
381
|
An array of angles given in radians.
|
|
348
382
|
center : float, optional
|
|
349
383
|
The center of rotation (CoR).
|
|
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.
|
|
350
387
|
recon_size : int, optional
|
|
351
388
|
The [recon_size, recon_size] shape of the reconstructed slice in pixels.
|
|
352
389
|
By default (None), the reconstructed size will be the dimension of the horizontal detector.
|
|
353
|
-
|
|
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
|
|
354
395
|
The number of CGLS iterations.
|
|
355
|
-
nonnegativity : bool
|
|
396
|
+
nonnegativity : bool
|
|
356
397
|
Impose nonnegativity constraint on reconstructed image.
|
|
357
398
|
neglog: bool
|
|
358
399
|
Take negative logarithm on input data to convert to attenuation coefficient or a density of the scanned object. Defaults to False,
|
|
@@ -368,24 +409,126 @@ def CGLS3d_tomobar(
|
|
|
368
409
|
data = data_checker(data, verbosity=True, method_name="CGLS3d_tomobar")
|
|
369
410
|
|
|
370
411
|
RecToolsCP = _instantiate_iterative_recon_class(
|
|
371
|
-
data, angles, center, recon_size, gpu_id, datafidelity="LS"
|
|
412
|
+
data, angles, center, detector_pad, recon_size, gpu_id, datafidelity="LS"
|
|
372
413
|
)
|
|
373
414
|
|
|
374
415
|
_data_ = {
|
|
375
416
|
"projection_norm_data": _take_neg_log(data) if neglog else data,
|
|
376
417
|
"data_axes_labels_order": input_data_axis_labels,
|
|
377
418
|
} # data dictionary
|
|
378
|
-
_algorithm_ = {
|
|
419
|
+
_algorithm_ = {
|
|
420
|
+
"iterations": iterations,
|
|
421
|
+
"nonnegativity": nonnegativity,
|
|
422
|
+
"recon_mask_radius": recon_mask_radius,
|
|
423
|
+
}
|
|
379
424
|
reconstruction = RecToolsCP.CGLS(_data_, _algorithm_)
|
|
380
425
|
cp._default_memory_pool.free_all_blocks()
|
|
381
426
|
return cp.require(cp.swapaxes(reconstruction, 0, 1), requirements="C")
|
|
382
427
|
|
|
383
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
|
+
|
|
384
526
|
## %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ##
|
|
385
527
|
def _instantiate_direct_recon_class(
|
|
386
528
|
data: cp.ndarray,
|
|
387
529
|
angles: np.ndarray,
|
|
388
530
|
center: Optional[float] = None,
|
|
531
|
+
detector_pad: Union[bool, int] = False,
|
|
389
532
|
recon_size: Optional[int] = None,
|
|
390
533
|
gpu_id: int = 0,
|
|
391
534
|
) -> Type:
|
|
@@ -395,6 +538,7 @@ def _instantiate_direct_recon_class(
|
|
|
395
538
|
data (cp.ndarray): data array
|
|
396
539
|
angles (np.ndarray): angles
|
|
397
540
|
center (Optional[float], optional): center of recon. Defaults to None.
|
|
541
|
+
detector_pad : (Union[bool, int]) : Detector width padding. Defaults to False.
|
|
398
542
|
recon_size (Optional[int], optional): recon_size. Defaults to None.
|
|
399
543
|
gpu_id (int, optional): gpu ID. Defaults to 0.
|
|
400
544
|
|
|
@@ -405,8 +549,13 @@ def _instantiate_direct_recon_class(
|
|
|
405
549
|
center = data.shape[2] // 2 # making a crude guess
|
|
406
550
|
if recon_size is None:
|
|
407
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
|
|
408
556
|
RecToolsCP = RecToolsDIRCuPy(
|
|
409
557
|
DetectorsDimH=data.shape[2], # Horizontal detector dimension
|
|
558
|
+
DetectorsDimH_pad=detector_pad, # padding for horizontal detector
|
|
410
559
|
DetectorsDimV=data.shape[1], # Vertical detector dimension (3D case)
|
|
411
560
|
CenterRotOffset=data.shape[2] / 2
|
|
412
561
|
- center
|
|
@@ -423,6 +572,7 @@ def _instantiate_direct_recon2d_class(
|
|
|
423
572
|
data: np.ndarray,
|
|
424
573
|
angles: np.ndarray,
|
|
425
574
|
center: Optional[float] = None,
|
|
575
|
+
detector_pad: Union[bool, int] = False,
|
|
426
576
|
recon_size: Optional[int] = None,
|
|
427
577
|
gpu_id: int = 0,
|
|
428
578
|
) -> Type:
|
|
@@ -432,6 +582,7 @@ def _instantiate_direct_recon2d_class(
|
|
|
432
582
|
data (cp.ndarray): data array
|
|
433
583
|
angles (np.ndarray): angles
|
|
434
584
|
center (Optional[float], optional): center of recon. Defaults to None.
|
|
585
|
+
detector_pad : (Union[bool, int]) : Detector width padding. Defaults to False.
|
|
435
586
|
recon_size (Optional[int], optional): recon_size. Defaults to None.
|
|
436
587
|
gpu_id (int, optional): gpu ID. Defaults to 0.
|
|
437
588
|
|
|
@@ -442,8 +593,13 @@ def _instantiate_direct_recon2d_class(
|
|
|
442
593
|
center = data.shape[2] // 2 # making a crude guess
|
|
443
594
|
if recon_size is None:
|
|
444
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
|
|
445
600
|
RecTools = RecToolsDIR(
|
|
446
601
|
DetectorsDimH=data.shape[2], # Horizontal detector dimension
|
|
602
|
+
DetectorsDimH_pad=detector_pad, # padding for horizontal detector
|
|
447
603
|
DetectorsDimV=None, # 2d case
|
|
448
604
|
CenterRotOffset=data.shape[2] / 2
|
|
449
605
|
- center
|
|
@@ -459,6 +615,7 @@ def _instantiate_iterative_recon_class(
|
|
|
459
615
|
data: cp.ndarray,
|
|
460
616
|
angles: np.ndarray,
|
|
461
617
|
center: Optional[float] = None,
|
|
618
|
+
detector_pad: Union[bool, int] = False,
|
|
462
619
|
recon_size: Optional[int] = None,
|
|
463
620
|
gpu_id: int = 0,
|
|
464
621
|
datafidelity: str = "LS",
|
|
@@ -469,6 +626,7 @@ def _instantiate_iterative_recon_class(
|
|
|
469
626
|
data (cp.ndarray): data array
|
|
470
627
|
angles (np.ndarray): angles
|
|
471
628
|
center (Optional[float], optional): center of recon. Defaults to None.
|
|
629
|
+
detector_pad : (Union[bool, int]) : Detector width padding. Defaults to False.
|
|
472
630
|
recon_size (Optional[int], optional): recon_size. Defaults to None.
|
|
473
631
|
datafidelity (str, optional): Data fidelity
|
|
474
632
|
gpu_id (int, optional): gpu ID. Defaults to 0.
|
|
@@ -480,8 +638,13 @@ def _instantiate_iterative_recon_class(
|
|
|
480
638
|
center = data.shape[2] // 2 # making a crude guess
|
|
481
639
|
if recon_size is None:
|
|
482
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
|
|
483
645
|
RecToolsCP = RecToolsIRCuPy(
|
|
484
646
|
DetectorsDimH=data.shape[2], # Horizontal detector dimension
|
|
647
|
+
DetectorsDimH_pad=detector_pad, # padding for horizontal detector
|
|
485
648
|
DetectorsDimV=data.shape[1], # Vertical detector dimension (3D case)
|
|
486
649
|
CenterRotOffset=data.shape[2] / 2
|
|
487
650
|
- center
|
|
@@ -510,3 +673,10 @@ def _take_neg_log_np(data: np.ndarray) -> np.ndarray:
|
|
|
510
673
|
data[np.isnan(data)] = 6.0
|
|
511
674
|
data[np.isinf(data)] = 0
|
|
512
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
|
+
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"
|
|
@@ -71,7 +70,7 @@ Conda environment
|
|
|
71
70
|
|
|
72
71
|
$ conda create --name httomolibgpu # create a fresh conda environment
|
|
73
72
|
$ conda activate httomolibgpu # activate the environment
|
|
74
|
-
$ conda install
|
|
73
|
+
$ conda install conda-forge::cupy==12.3.0
|
|
75
74
|
$ pip install httomolibgpu
|
|
76
75
|
|
|
77
76
|
Setup the development environment:
|
|
@@ -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
|
-
httomolibgpu/misc/corr.py,sha256=
|
|
13
|
-
httomolibgpu/misc/denoise.py,sha256=
|
|
11
|
+
httomolibgpu/misc/corr.py,sha256=1tUjwMku-MAPiLaH9IFe3zmF0p6rJFLruoObXSZelXY,4665
|
|
12
|
+
httomolibgpu/misc/denoise.py,sha256=l5FVdpur1I6YQcJJBfYTKjEsiDNyRYtpdOQZ7ZHicJw,4997
|
|
14
13
|
httomolibgpu/misc/morph.py,sha256=AlLk_kGFHF6vNrdICMpsXmTUDnCc7ey97-_DqwZb3Wc,7475
|
|
15
|
-
httomolibgpu/misc/rescale.py,sha256=
|
|
16
|
-
httomolibgpu/misc/supp_func.py,sha256=
|
|
14
|
+
httomolibgpu/misc/rescale.py,sha256=K4VQ1AdxOAhe8tTSVb9VXVZsjBap5VlOtxHVdf9MU08,4416
|
|
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-
|
|
26
|
-
httomolibgpu-
|
|
27
|
-
httomolibgpu-
|
|
28
|
-
httomolibgpu-
|
|
29
|
-
httomolibgpu-
|
|
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
|