httomolibgpu 5.7__tar.gz → 5.8.1__tar.gz

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.
Files changed (37) hide show
  1. {httomolibgpu-5.7/httomolibgpu.egg-info → httomolibgpu-5.8.1}/PKG-INFO +2 -1
  2. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/misc/morph.py +63 -0
  3. httomolibgpu-5.8.1/httomolibgpu/misc/sorting.py +56 -0
  4. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/prep/stripe.py +20 -34
  5. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/recon/algorithm.py +7 -5
  6. {httomolibgpu-5.7 → httomolibgpu-5.8.1/httomolibgpu.egg-info}/PKG-INFO +2 -1
  7. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu.egg-info/SOURCES.txt +1 -0
  8. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu.egg-info/requires.txt +1 -0
  9. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/pyproject.toml +2 -1
  10. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/LICENSE +0 -0
  11. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/MANIFEST.in +0 -0
  12. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/README.rst +0 -0
  13. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/__init__.py +0 -0
  14. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/cuda_kernels/__init__.py +0 -0
  15. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/cuda_kernels/calc_metrics.cu +0 -0
  16. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/cuda_kernels/center_360_shifts.cu +0 -0
  17. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/cuda_kernels/generate_mask.cu +0 -0
  18. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/cuda_kernels/median_kernel.cu +0 -0
  19. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/cuda_kernels/raven_filter.cu +0 -0
  20. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/cuda_kernels/remove_nan_inf.cu +0 -0
  21. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/cuda_kernels/remove_stripe_fw.cu +0 -0
  22. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/cupywrapper.py +0 -0
  23. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/misc/__init__.py +0 -0
  24. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/misc/corr.py +0 -0
  25. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/misc/denoise.py +0 -0
  26. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/misc/rescale.py +0 -0
  27. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/misc/utils.py +0 -0
  28. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/prep/__init__.py +0 -0
  29. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/prep/alignment.py +0 -0
  30. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/prep/normalize.py +0 -0
  31. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/prep/phase.py +0 -0
  32. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/recon/__init__.py +0 -0
  33. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/recon/_phase_cross_correlation.py +0 -0
  34. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu/recon/rotation.py +0 -0
  35. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu.egg-info/dependency_links.txt +0 -0
  36. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/httomolibgpu.egg-info/top_level.txt +0 -0
  37. {httomolibgpu-5.7 → httomolibgpu-5.8.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: httomolibgpu
3
- Version: 5.7
3
+ Version: 5.8.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
@@ -33,6 +33,7 @@ Requires-Dist: imageio; extra == "dev"
33
33
  Requires-Dist: h5py; extra == "dev"
34
34
  Requires-Dist: pre-commit; extra == "dev"
35
35
  Requires-Dist: pyfftw; extra == "dev"
36
+ Requires-Dist: tomophantom; extra == "dev"
36
37
  Dynamic: license-file
37
38
 
38
39
  HTTomolibGPU is a library of GPU accelerated methods for tomography
@@ -45,6 +45,7 @@ from httomolibgpu.misc.utils import (
45
45
  __all__ = [
46
46
  "sino_360_to_180",
47
47
  "data_resampler",
48
+ "average_projection_frames",
48
49
  ]
49
50
 
50
51
 
@@ -305,3 +306,65 @@ def data_resampler(
305
306
  if expanded:
306
307
  scaled_data = cp.squeeze(scaled_data, axis=axis)
307
308
  return scaled_data
309
+
310
+
311
+ def average_projection_frames(
312
+ data: cp.ndarray,
313
+ projection_averaging_factor: int = 2,
314
+ ) -> cp.ndarray:
315
+ """
316
+ This method averages/downsamples by averaging data along the angular direction based on the provided projection_averaging_factor.
317
+
318
+ Parameters
319
+ ----------
320
+ data : cp.ndarray
321
+ 3d cupy array given as (angles, detY, detX).
322
+ projection_averaging_factor : int
323
+ to average every (defined by the provided factor) consecutive projections into one effective projection.
324
+
325
+ Raises
326
+ ----------
327
+ ValueError: When data is not 3D
328
+
329
+ Returns
330
+ -------
331
+ cp.ndarray: 3D cupy array with averaged projection data
332
+ """
333
+
334
+ ### Data and parameters checks ###
335
+ methods_name = "average_projection_frames"
336
+ __check_if_data_3D_array(data, methods_name)
337
+ __check_if_data_correct_type(
338
+ data, accepted_type=["float32", "uint16"], methods_name=methods_name
339
+ )
340
+ __check_if_positive_nonzero(
341
+ projection_averaging_factor,
342
+ "projection_averaging_factor",
343
+ True,
344
+ True,
345
+ methods_name,
346
+ )
347
+
348
+ ###################################
349
+ if projection_averaging_factor > 1:
350
+ k = projection_averaging_factor
351
+ n_proj = data.shape[0]
352
+
353
+ n_full = n_proj // k
354
+ remainder = n_proj % k
355
+
356
+ n_out = n_full + (remainder > 0)
357
+
358
+ averaged = cp.empty((n_out, *data.shape[1:]), dtype=data.dtype)
359
+
360
+ if n_full:
361
+ averaged[:n_full] = (
362
+ data[: n_full * k].reshape(n_full, k, *data.shape[1:]).mean(axis=1)
363
+ )
364
+
365
+ if remainder:
366
+ averaged[-1] = data[n_full * k :].mean(axis=0)
367
+
368
+ return averaged
369
+ else:
370
+ return data
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # ---------------------------------------------------------------------------
4
+ # Copyright 2026 Diamond Light Source Ltd.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either ecpress or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ # ---------------------------------------------------------------------------
18
+ # Created By : Tomography Team at DLS <scientificsoftware@diamond.ac.uk>
19
+ # Created Date: 22 April 2026
20
+ # ---------------------------------------------------------------------------
21
+
22
+ from typing import Tuple
23
+ from httomolibgpu import cupywrapper
24
+
25
+ cp = cupywrapper.cp
26
+
27
+
28
+ def argsort_with_reverse(
29
+ data: cp.ndarray, axis: int = -1
30
+ ) -> Tuple[cp.ndarray, cp.ndarray]:
31
+ """
32
+ Compute sorting indices for an 1D or 2D array, and efficiently compute the indices to revert the sort.
33
+ """
34
+ dim = len(data.shape)
35
+ if 1 <= dim <= 2:
36
+ pass
37
+ else:
38
+ raise ValueError("only 1D and 2D arrays are supported")
39
+ if axis < 0:
40
+ axis = dim + axis
41
+ if axis >= dim:
42
+ raise ValueError("invalid axis")
43
+ sort_indices = cp.argsort(data, axis=axis)
44
+ reverse_sort_indices = cp.empty_like(sort_indices)
45
+ if dim == 1:
46
+ reverse_sort_indices[sort_indices] = cp.arange(0, data.size)
47
+ elif axis == 0: # sort rows
48
+ nrows, ncols = data.shape
49
+ cols = cp.arange(ncols)[None, :]
50
+ reverse_sort_indices[sort_indices, cols] = cp.arange(nrows)[:, None]
51
+ else: # sort columns
52
+ nrows, ncols = data.shape
53
+ rows = cp.arange(nrows)[:, None]
54
+ reverse_sort_indices[rows, sort_indices] = cp.arange(ncols)
55
+
56
+ return sort_indices, reverse_sort_indices
@@ -23,6 +23,7 @@
23
23
  import numpy as np
24
24
  import pywt
25
25
  from httomolibgpu import cupywrapper
26
+ from httomolibgpu.misc.sorting import argsort_with_reverse
26
27
 
27
28
  cp = cupywrapper.cp
28
29
  cupy_run = cupywrapper.cupy_run
@@ -116,21 +117,18 @@ def _rs_sort(sinogram, size, dim):
116
117
  """
117
118
  Remove stripes using the sorting technique.
118
119
  """
119
- sinogram = cp.transpose(sinogram)
120
+ #: Sort each row of the sinogram by its grayscale values
121
+ sortvals, sortvals_reverse = argsort_with_reverse(sinogram, axis=0)
120
122
 
121
- #: Sort each column of the sinogram by its grayscale values
122
- #: Keep track of the sorting indices so we can reverse it below
123
- sortvals = cp.argsort(sinogram, axis=1)
124
- sortvals_reverse = cp.argsort(sortvals, axis=1)
125
- sino_sort = cp.take_along_axis(sinogram, sortvals, axis=1)
123
+ sino_sort = cp.take_along_axis(sinogram, sortvals, axis=0)
126
124
 
127
125
  #: Now apply the median filter on the sorted image along each row
128
- sino_sort = median_filter(sino_sort, (size, 1) if dim == 1 else (size, size))
126
+ sino_sort = median_filter(sino_sort, (1, size) if dim == 1 else (size, size))
129
127
 
130
128
  #: step 3: re-sort the smoothed image columns to the original rows
131
- sino_corrected = cp.take_along_axis(sino_sort, sortvals_reverse, axis=1)
129
+ sino_corrected = cp.take_along_axis(sino_sort, sortvals_reverse, axis=0)
132
130
 
133
- return cp.transpose(sino_corrected)
131
+ return sino_corrected
134
132
 
135
133
 
136
134
  def remove_stripe_ti(
@@ -821,6 +819,7 @@ def remove_all_stripe(
821
819
  la_size: int = 61,
822
820
  sm_size: int = 21,
823
821
  dim: Literal[1, 2] = 1,
822
+ normalize: bool = False,
824
823
  ) -> cp.ndarray:
825
824
  """
826
825
  Remove all types of stripe artifacts from sinogram using Nghia Vo's
@@ -839,6 +838,8 @@ def remove_all_stripe(
839
838
  Window size of the median filter to remove small-to-medium stripes.
840
839
  dim : {1, 2},
841
840
  Dimension of the window.
841
+ normalize : bool,
842
+ Controls whether to normalize while removing large stripes
842
843
 
843
844
  Returns
844
845
  -------
@@ -859,10 +860,10 @@ def remove_all_stripe(
859
860
  __check_variable_type(dim, [int], "dim", [1, 2], methods_name)
860
861
  ###################################
861
862
 
862
- matindex = _create_matindex(data.shape[2], data.shape[0])
863
863
  for m in range(data.shape[1]):
864
864
  sino = data[:, m, :]
865
- sino = _rs_dead(sino, snr, la_size, matindex)
865
+ sino = _rs_dead(sino, snr, la_size)
866
+ sino = _rs_large(sino, snr, la_size, normalize)
866
867
  sino = _rs_sort(sino, sm_size, dim)
867
868
  sino = cp.nan_to_num(sino)
868
869
  data[:, m, :] = sino
@@ -910,15 +911,17 @@ def _detect_stripe(listdata, snr):
910
911
  return listmask
911
912
 
912
913
 
913
- def _rs_large(sinogram, snr, size, matindex, drop_ratio=0.1, norm=True):
914
+ def _rs_large(sinogram, snr, size, normalize, drop_ratio=0.1):
914
915
  """
915
916
  Remove large stripes.
916
917
  """
917
918
  drop_ratio = max(min(drop_ratio, 0.8), 0) # = cp.clip(drop_ratio, 0.0, 0.8)
918
919
  nrow, ncol = sinogram.shape
919
920
  ndrop = int(0.5 * drop_ratio * nrow)
920
- sinosort = cp.sort(sinogram, axis=0)
921
+ sort_indices, sort_indices_reverse = argsort_with_reverse(sinogram, axis=0)
922
+ sinosort = cp.take_along_axis(sinogram, sort_indices, axis=0)
921
923
  sinosmooth = median_filter(sinosort, (1, size))
924
+
922
925
  list1 = cp.mean(sinosort[ndrop : nrow - ndrop], axis=0)
923
926
  list2 = cp.mean(sinosmooth[ndrop : nrow - ndrop], axis=0)
924
927
  listfact = list1 / list2
@@ -927,30 +930,16 @@ def _rs_large(sinogram, snr, size, matindex, drop_ratio=0.1, norm=True):
927
930
  listmask = _detect_stripe(listfact, snr)
928
931
  listmask = binary_dilation(listmask, iterations=1).astype(listmask.dtype)
929
932
  matfact = cp.tile(listfact, (nrow, 1))
930
- # Normalize
931
- if norm is True:
933
+ if normalize:
932
934
  sinogram = sinogram / matfact
933
- sinogram1 = cp.transpose(sinogram)
934
- matcombine = cp.asarray(cp.dstack((matindex, sinogram1)))
935
-
936
- ids = cp.argsort(matcombine[:, :, 1], axis=1)
937
- matsort = matcombine.copy()
938
- matsort[:, :, 0] = cp.take_along_axis(matsort[:, :, 0], ids, axis=1)
939
- matsort[:, :, 1] = cp.take_along_axis(matsort[:, :, 1], ids, axis=1)
940
-
941
- matsort[:, :, 1] = cp.transpose(sinosmooth)
942
- ids = cp.argsort(matsort[:, :, 0], axis=1)
943
- matsortback = matsort.copy()
944
- matsortback[:, :, 0] = cp.take_along_axis(matsortback[:, :, 0], ids, axis=1)
945
- matsortback[:, :, 1] = cp.take_along_axis(matsortback[:, :, 1], ids, axis=1)
946
-
947
- sino_corrected = cp.transpose(matsortback[:, :, 1])
935
+ sort_indices, sort_indices_reverse = argsort_with_reverse(sinogram, axis=0)
936
+ sino_corrected = cp.take_along_axis(sinosmooth, sort_indices_reverse, axis=0)
948
937
  listxmiss = cp.where(listmask > 0.0)[0]
949
938
  sinogram[:, listxmiss] = sino_corrected[:, listxmiss]
950
939
  return sinogram
951
940
 
952
941
 
953
- def _rs_dead(sinogram, snr, size, matindex, norm=True):
942
+ def _rs_dead(sinogram, snr, size):
954
943
  """remove unresponsive and fluctuating stripes"""
955
944
  sinogram = cp.copy(sinogram) # Make it mutable
956
945
  nrow, _ = sinogram.shape
@@ -979,9 +968,6 @@ def _rs_dead(sinogram, snr, size, matindex, norm=True):
979
968
  sinogram[:, listx[ids]] - sinogram[:, listx[ids - 1]]
980
969
  )
981
970
 
982
- # Remove residual stripes
983
- if norm is True:
984
- sinogram = _rs_large(sinogram, snr, size, matindex)
985
971
  return sinogram
986
972
 
987
973
 
@@ -566,13 +566,13 @@ def FISTA3d_tomobar(
566
566
  data_fidelity: str
567
567
  Data fidelity given as 'LS' (Least Squares)
568
568
  regularisation_type: str
569
- A method to use for regularisation. Currently PD_TV and ROF_TV are available.
569
+ A method to use for regularisation. Currently PD_TV and ROF_TV penalties are available.
570
570
  regularisation_parameter: float
571
571
  The main regularisation parameter to control the amount of smoothing/noise removal. Larger values lead to stronger smoothing.
572
572
  regularisation_iterations: int
573
573
  The number of iterations for regularisers (aka INNER iterations).
574
574
  regularisation_half_precision: bool
575
- Perform faster regularisation computation in half-precision with a very minimal sacrifice in quality.
575
+ Perform faster regularisation computation in half-precision with some sacrifice in quality (can be used to find the best settings).
576
576
  nonnegativity : bool
577
577
  Impose nonnegativity constraint on the reconstructed image.
578
578
  gpu_id : int
@@ -698,14 +698,16 @@ def ADMM3d_tomobar(
698
698
  ADMM_rho_const: float
699
699
  Convergence related parameter for ADMM, higher values lead to slower convergence, but too small values can destabilise the iterations.
700
700
  Recommended range is between 0.9 and 2.0.
701
- ADMM_relax_par: Relaxation parameter which can lead to acceleration of the algorithm, keep it in the range between 1.5 and 1.8 to avoid divergence. regularisation_type: str
702
- A method to use for regularisation. Currently PD_TV and ROF_TV are available.
701
+ ADMM_relax_par: float
702
+ Relaxation parameter which can lead to acceleration of the algorithm, keep it in the range between 1.5 and 1.8 to avoid divergence.
703
+ regularisation_type: str
704
+ A method to use for regularisation. Currently PD_TV and ROF_TV penalties are available.
703
705
  regularisation_parameter: float
704
706
  The main regularisation parameter to control the amount of smoothing/noise removal. Larger values lead to stronger smoothing.
705
707
  regularisation_iterations: int
706
708
  The number of iterations for regularisers (aka INNER iterations).
707
709
  regularisation_half_precision: bool
708
- Perform faster regularisation computation in half-precision with a very minimal sacrifice in quality.
710
+ Perform faster regularisation computation in half-precision with some sacrifice in quality (can be used to find the best settings).
709
711
  nonnegativity : bool
710
712
  Impose nonnegativity constraint (set to True) on the reconstructed image. Default False.
711
713
  gpu_id : int
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: httomolibgpu
3
- Version: 5.7
3
+ Version: 5.8.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
@@ -33,6 +33,7 @@ Requires-Dist: imageio; extra == "dev"
33
33
  Requires-Dist: h5py; extra == "dev"
34
34
  Requires-Dist: pre-commit; extra == "dev"
35
35
  Requires-Dist: pyfftw; extra == "dev"
36
+ Requires-Dist: tomophantom; extra == "dev"
36
37
  Dynamic: license-file
37
38
 
38
39
  HTTomolibGPU is a library of GPU accelerated methods for tomography
@@ -22,6 +22,7 @@ httomolibgpu/misc/corr.py
22
22
  httomolibgpu/misc/denoise.py
23
23
  httomolibgpu/misc/morph.py
24
24
  httomolibgpu/misc/rescale.py
25
+ httomolibgpu/misc/sorting.py
25
26
  httomolibgpu/misc/utils.py
26
27
  httomolibgpu/prep/__init__.py
27
28
  httomolibgpu/prep/alignment.py
@@ -20,3 +20,4 @@ imageio
20
20
  h5py
21
21
  pre-commit
22
22
  pyfftw
23
+ tomophantom
@@ -60,7 +60,8 @@ dev = [
60
60
  "imageio",
61
61
  "h5py",
62
62
  "pre-commit",
63
- "pyfftw"
63
+ "pyfftw",
64
+ "tomophantom"
64
65
  ]
65
66
 
66
67
 
File without changes
File without changes
File without changes
File without changes