nabu 2025.1.0rc2__py3-none-any.whl → 2025.1.0rc3__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.
nabu/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "2025.1.0-rc2"
1
+ __version__ = "2025.1.0-rc3"
2
2
  __nabu_modules__ = [
3
3
  "app",
4
4
  "cuda",
nabu/app/cli_configs.py CHANGED
@@ -654,6 +654,12 @@ ReduceDarkFlatConfig = {
654
654
 
655
655
  PCAFlatsConfig = {
656
656
  "datasets": {"help": "datasets to be stitched together", "default": tuple(), "nargs": "+", "mandatory": True},
657
+ "nsigma": {
658
+ "help": "Paramter to select PCA components. Default is 3. Higher nsigma, less components.",
659
+ "default": 3.0,
660
+ "type": float,
661
+ "required": False,
662
+ },
657
663
  "flat-method": {
658
664
  "help": f"Define the method to be used for computing flats. Valid methods are {reduce_methods}",
659
665
  "default": ReduceMethod.MEDIAN,
nabu/app/pcaflats.py CHANGED
@@ -42,10 +42,12 @@ def get_flats_darks_from_h5(filename):
42
42
  return flats, darks, "entry0000" # TODO this will be problematic on the reconstruction side
43
43
 
44
44
 
45
- def pcaflats_decomposition(flats, darks, pcaflats_filename="PCAFlats.h5", overwrite=False, entry="entry0000"):
45
+ def pcaflats_decomposition(
46
+ flats, darks, pcaflats_filename="PCAFlats.h5", overwrite=False, entry="entry0000", nsigma=3.0
47
+ ):
46
48
  """Compute the PCS decomposition of a series of flats and darks, possibly taken from various scans."""
47
49
  try:
48
- decomposer = PCAFlatsDecomposer(flats, darks)
50
+ decomposer = PCAFlatsDecomposer(flats, darks, nsigma=nsigma)
49
51
  decomposer.save_decomposition(pcaflats_filename, overwrite=overwrite, entry=entry)
50
52
  success = True
51
53
  except:
@@ -74,7 +76,11 @@ def main(argv=None):
74
76
  )
75
77
 
76
78
  # Get "where to write".
77
- abspath = os.path.abspath(args["output_filename"])
79
+ if args["output_filename"] is None:
80
+ abspath = os.path.abspath("./PCAFlats.hdf5")
81
+ else:
82
+ abspath = os.path.abspath(args["output_filename"])
83
+
78
84
  pcaflats_dir = os.path.dirname(abspath)
79
85
  pcaflats_filename = os.path.basename(abspath)
80
86
 
@@ -107,7 +113,7 @@ def main(argv=None):
107
113
 
108
114
  exit(
109
115
  pcaflats_decomposition(
110
- flats, darks, pcaflats_filename=args["output_filename"], overwrite=args["overwrite"], entry=entry
116
+ flats, darks, pcaflats_filename=output_path, overwrite=args["overwrite"], entry=entry, nsigma=args["nsigma"]
111
117
  )
112
118
  )
113
119
 
nabu/cuda/src/backproj.cu CHANGED
@@ -132,10 +132,10 @@ __global__ void backproj(
132
132
  sum3 += tex2D(tex_projections, h3 + 0.5f, proj + 0.5f);
133
133
  sum4 += tex2D(tex_projections, h4 + 0.5f, proj + 0.5f);
134
134
  #else
135
- sum1 += linear_interpolation(d_sino, num_bins, h1, proj);
136
- sum2 += linear_interpolation(d_sino, num_bins, h2, proj);
137
- sum3 += linear_interpolation(d_sino, num_bins, h3, proj);
138
- sum4 += linear_interpolation(d_sino, num_bins, h4, proj);
135
+ if (h1 >= 0 && h1 < num_bins) sum1 += linear_interpolation(d_sino, num_bins, h1, proj);
136
+ if (h2 >= 0 && h2 < num_bins) sum2 += linear_interpolation(d_sino, num_bins, h2, proj);
137
+ if (h3 >= 0 && h3 < num_bins) sum3 += linear_interpolation(d_sino, num_bins, h3, proj);
138
+ if (h4 >= 0 && h4 < num_bins) sum4 += linear_interpolation(d_sino, num_bins, h4, proj);
139
139
  #endif
140
140
  }
141
141
 
nabu/io/cast_volume.py CHANGED
@@ -250,6 +250,9 @@ def cast_volume(
250
250
  # if no metadata provided and or saved in disk or if some key are missing
251
251
  pass
252
252
 
253
+ if save and output_volume.metadata is not None:
254
+ output_volume.save_metadata()
255
+
253
256
  if remove_input_volume:
254
257
  _logger.info(f"Removing {input_volume.data_url.file_path()}")
255
258
  remove_volume(input_volume, check=True)
@@ -116,10 +116,10 @@ kernel void backproj(
116
116
  sum3 += read_imagef(d_sino, sampler, (float2) (h3 +0.5f,proj +0.5f)).x;
117
117
  sum4 += read_imagef(d_sino, sampler, (float2) (h4 +0.5f,proj +0.5f)).x;
118
118
  #else
119
- sum1 += linear_interpolation(d_sino, num_bins, h1, proj);
120
- sum2 += linear_interpolation(d_sino, num_bins, h2, proj);
121
- sum3 += linear_interpolation(d_sino, num_bins, h3, proj);
122
- sum4 += linear_interpolation(d_sino, num_bins, h4, proj);
119
+ if (h1 >= 0 && h1 < num_bins) sum1 += linear_interpolation(d_sino, num_bins, h1, proj);
120
+ if (h2 >= 0 && h2 < num_bins) sum2 += linear_interpolation(d_sino, num_bins, h2, proj);
121
+ if (h3 >= 0 && h3 < num_bins) sum3 += linear_interpolation(d_sino, num_bins, h3, proj);
122
+ if (h4 >= 0 && h4 < num_bins) sum4 += linear_interpolation(d_sino, num_bins, h4, proj);
123
123
  #endif
124
124
  }
125
125
 
@@ -86,8 +86,6 @@ class ProcessConfig(ProcessConfigBase):
86
86
  elif self.dataset_info.kind == "edf":
87
87
  self.dataset_info.flats = self.dataset_info.get_reduced_flats()
88
88
  self.dataset_info.darks = self.dataset_info.get_reduced_darks()
89
- else:
90
- raise TypeError("Unknown dataset format")
91
89
  self.rec_params = self.nabu_config["reconstruction"]
92
90
 
93
91
  subsampling_factor, subsampling_start = self.nabu_config["dataset"]["projections_subsampling"]
nabu/preproc/ccd.py CHANGED
@@ -167,7 +167,7 @@ class CCDFilter:
167
167
  med = self.median_filter(dimg, self.kernel_size)
168
168
  err = dimg - med
169
169
  ds0 = err.std()
170
- msk = err > ds0 * nsigma
170
+ msk = err > (ds0 * nsigma)
171
171
  gromsk = binary_dilation(msk)
172
172
 
173
173
  output[i] = np.where(gromsk, med, radios[i])
nabu/preproc/flatfield.py CHANGED
@@ -669,7 +669,7 @@ class PCAFlatsDecomposer:
669
669
  def _ccdfilter_and_log(self, flats: np.ndarray):
670
670
  """Dezinger (substract dark, apply median filter) and takes log of the flat stack"""
671
671
 
672
- self.ccdfilter.dezinger_correction(flats, self.dark, nsigma=self.nsigma)
672
+ self.ccdfilter.dezinger_correction(flats, self.dark)
673
673
 
674
674
  with ThreadPool(self.n_threads) as tp:
675
675
  for i, frame in enumerate(tp.map(np.log, flats)):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nabu
3
- Version: 2025.1.0rc2
3
+ Version: 2025.1.0rc3
4
4
  Summary: Nabu - Tomography software
5
5
  Author-email: Pierre Paleo <pierre.paleo@esrf.fr>, Henri Payno <henri.payno@esrf.fr>, Alessandro Mirone <mirone@esrf.fr>, Jérôme Lesaint <jerome.lesaint@esrf.fr>
6
6
  Maintainer-email: Pierre Paleo <pierre.paleo@esrf.fr>
@@ -32,7 +32,7 @@ Requires-Dist: numpy>1.9.0
32
32
  Requires-Dist: scipy
33
33
  Requires-Dist: h5py>=3.0
34
34
  Requires-Dist: silx>=0.15.0
35
- Requires-Dist: tomoscan>=2.2.0
35
+ Requires-Dist: tomoscan>=2.2.2
36
36
  Requires-Dist: psutil
37
37
  Requires-Dist: pytest
38
38
  Requires-Dist: tifffile
@@ -1,8 +1,7 @@
1
1
  doc/conf.py,sha256=3xtCarCHrXPr50GbeRDuH-o3Jzojw7mpr7vpGfZPLAE,3787
2
2
  doc/create_conf_doc.py,sha256=IVOdP70KvbW9WS_UQu3Iyd0YfS60E2fJ5IDtQ_s4cDw,1143
3
- doc/doc_config.py,sha256=anqeOVjqE2e7eVzg7yuh9dvIneTkrA5doGl1cVBqT7Q,730
4
3
  doc/get_mathjax.py,sha256=VIvKRCdDuF2VoY8JD3mSey9XX13AZMmwTJBHdt1tUs4,1012
5
- nabu/__init__.py,sha256=QueX4--BpvfYX_Z3n6mCQ68QSUVU7ffJx7fyF8CRDJ0,274
4
+ nabu/__init__.py,sha256=weQJf5hGEi-BzNCLAkn3BNQ71AJRC7nINDlNmkELmCc,274
6
5
  nabu/tests.py,sha256=hOJD1GGxn_KE1bWMoxfjnjzI7d9JBUpoc9B2_tVFiEk,1370
7
6
  nabu/testutils.py,sha256=eL81DWgYwu2CCFmDMsFs4QjfI7w9RPXFuPU5gvYF6No,8631
8
7
  nabu/utils.py,sha256=tJI64BNXMhD6W293fwwcgf9bvTalYG_5AwVGYkgi6tU,27179
@@ -10,7 +9,7 @@ nabu/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
9
  nabu/app/bootstrap.py,sha256=3yLZJmrmQBmPJMBtE2ih2cspfqOy5T_UN2U8B3i_hkI,3266
11
10
  nabu/app/bootstrap_stitching.py,sha256=wCKgugOQr6-lPMWEn4AYQeric0tCuRc9O-RnpBuTWAA,2230
12
11
  nabu/app/cast_volume.py,sha256=OufJDx_ZJ-ZbhbvIPHxRox4jtL6PfWcL148g77BWCDU,11454
13
- nabu/app/cli_configs.py,sha256=D3KaMVnZ9eLnSzgSJmdNWhxF0GESbmXMYiNeOBzu1vY,24794
12
+ nabu/app/cli_configs.py,sha256=paHLX7ZDmTKhiXF9ZDzo18ld7H1HoOpaO8YnHPAqwhc,24991
14
13
  nabu/app/compare_volumes.py,sha256=3qm3QsxV-D_myLAkhM_LlX0DTrDmhzfhrnNak-1538Q,3337
15
14
  nabu/app/composite_cor.py,sha256=-qAbMJCFa0NmSb1hO2G1QvdW4fwEXSMBBbSFCnQXmCc,5068
16
15
  nabu/app/create_distortion_map_from_poly.py,sha256=aa-vE-ndB9PsuHwdHUW7-8jGz4BxvjC-bQDWHlPV0Kg,6193
@@ -23,7 +22,7 @@ nabu/app/histogram.py,sha256=gyLXKwFrU5WPQMkM1k8OdpIXSwGEEKC-f8RcTHKOho4,7930
23
22
  nabu/app/multicor.py,sha256=FjmJurruRmrwXF7v56KlTszQGIGsqft1_P7AKR9feY0,4726
24
23
  nabu/app/nx_z_splitter.py,sha256=p54jR-PAAw-AkGolM9fZE5lM2vbNLspCNCy5zBnJNP4,4976
25
24
  nabu/app/parse_reconstruction_log.py,sha256=msOtA3xaqLZpISRqS0F9_SrkvbdvKNPE99tdWhPrkY0,4745
26
- nabu/app/pcaflats.py,sha256=R1udJSdJwfGwBL557HoPH6dVzka7ULMFI0JHUZfR7ds,4018
25
+ nabu/app/pcaflats.py,sha256=mzZzRvZKqVJAbzj75gYrlDqDzP1fpy_H5QCdjD-ivCw,4170
27
26
  nabu/app/prepare_weights_double.py,sha256=jy78aP1UNKqSk82Wy6ZCkKjpYXxaGmlIj_vjB4SxS8A,5443
28
27
  nabu/app/reconstruct.py,sha256=g_pkrs11QFuclgxKLih1JCRLhyM-Ln8ACXlMspA2phc,5681
29
28
  nabu/app/reconstruct_helical.py,sha256=cMjcc8IUGUtqAOfObsznLkcGm6Ev4ZoE_vJa--fDSNQ,4257
@@ -44,7 +43,7 @@ nabu/cuda/padding.py,sha256=x6lk6_SoHzruHbQZCdN-FTgE4JlN3hyrtm3k6wwANZM,230
44
43
  nabu/cuda/processing.py,sha256=nefntcARa917yirZqe5c90yPXua_sGzVUtg6Fzc2Vu8,2655
45
44
  nabu/cuda/utils.py,sha256=C-0-X3mWXgUzHrEKqX0hXpir1M5M6wx1Im-HdEVIYBc,9628
46
45
  nabu/cuda/src/ElementOp.cu,sha256=PhebQQgeF0V7MDNzeYiRXIeNq3tE2PsBx00XhanBmvg,7188
47
- nabu/cuda/src/backproj.cu,sha256=XPKiW4s72Rk3Uj_T96E6tPRLwna0Fe01087sFg1VmUw,6077
46
+ nabu/cuda/src/backproj.cu,sha256=EsJtb-HKK6hNnTzIYxK8B8YkgvuKJd2LC_seE-OzSbI,6197
48
47
  nabu/cuda/src/backproj_polar.cu,sha256=sZbtw3KMfN69XyubJQSSLC87d5IPOyzbPBoRSNC1Cek,1851
49
48
  nabu/cuda/src/boundary.h,sha256=eQhfKZm-o0kj88BvkUwzqfqxYfRde4Tuj8AhQvRK16Y,2898
50
49
  nabu/cuda/src/cone.cu,sha256=BcW6eLhYVnJZ9WgyD8F35-fGtVeggFv01ZxuWkmCZ_g,3533
@@ -82,7 +81,7 @@ nabu/estimation/tests/test_motion_estimation.py,sha256=WKUpkVand8VszoBIvsaEnhKqv
82
81
  nabu/estimation/tests/test_tilt.py,sha256=KIgTJqQvNfWndm8f3aRSdznWFl3AdQhYXiZPKLseYOs,1672
83
82
  nabu/estimation/tests/test_translation.py,sha256=RkOnCYgk9DZGKlIka1snqTv4wbIz_nG7-EHAxnBHsJU,2999
84
83
  nabu/io/__init__.py,sha256=AbQgj4-fCCHOKynO_PyAR9ejnFSuWKgroxxhxWVpjyQ,120
85
- nabu/io/cast_volume.py,sha256=Kn9BtAx0FAmCd57W6C8WTk1jp5j1l6mrIo45SYFVrvg,21408
84
+ nabu/io/cast_volume.py,sha256=eJuiKuZILD3xClUtYOjCqmwnbW12gwg-gJTzj606u_Y,21499
86
85
  nabu/io/detector_distortion.py,sha256=qO1Z6gejkBrixThvU_sLwH3UfLAe8aAO63YQ8z7PH78,11750
87
86
  nabu/io/reader.py,sha256=M6kLLzDe-OLh4veNr_F1Nn4TT6E6RfBpWPxMxrsnL94,41324
88
87
  nabu/io/reader_helical.py,sha256=q3LOmu6F_4Uxi3rZZWJ-rsix2Lgu_saXXdiJF8TLi24,4533
@@ -122,7 +121,7 @@ nabu/opencl/padding.py,sha256=CjeifU4xcUhgD_OILoIC4vPDQGVyVRjJXsMb8gxPL_0,238
122
121
  nabu/opencl/processing.py,sha256=cKq_VLtLBPijp2pl7Zgc4mrVsYLUA27x26jPo484Kg4,2416
123
122
  nabu/opencl/utils.py,sha256=OPqSJAZ82EwRmqu_H5_S59Y9a3CrqQhEQomWQj-EuSU,10239
124
123
  nabu/opencl/src/ElementOp.cl,sha256=RMScHhHYDa6xXC4NLJrC1KpDRq-aMZG1lwq3O9pStiY,1258
125
- nabu/opencl/src/backproj.cl,sha256=PVyCmlw2Jj_4tgdmY1NGFxg0WMfrhxIZ1W9ShcpoghI,5350
124
+ nabu/opencl/src/backproj.cl,sha256=BmikalwFHhqO8xSWGq_txnkrkeAja5SlVcxhFxH2jIw,5470
126
125
  nabu/opencl/src/fftshift.cl,sha256=xq-HNRWhuXqTVD_nD-38_41HPYZPCXAHDTpxsGURSTY,1726
127
126
  nabu/opencl/src/halftomo.cl,sha256=IZ2VJwWLpfaNpzM8Ief13zsqDcq68lyFqG55qYWoHNE,1386
128
127
  nabu/opencl/src/padding.cl,sha256=0e4wDB3wOVFIFw0f7VTfD45PK6HzDhooCgK2DZqiUfA,460
@@ -148,7 +147,7 @@ nabu/pipeline/fullfield/computations.py,sha256=uqf7LvuDPm7n51BpP8eb8vTewDgRFyzSD
148
147
  nabu/pipeline/fullfield/dataset_validator.py,sha256=HK_bmlII9pc59PXCgKJOyLv7Xu3DYv_jbH3RmQSgzvI,2933
149
148
  nabu/pipeline/fullfield/get_double_flatfield.py,sha256=uYFDAii6Nw4RCUQO_6Id6tXLdmtVbj_pxAHQWennSeE,5411
150
149
  nabu/pipeline/fullfield/nabu_config.py,sha256=F1E4KwHTfw6tynBnBjvr1F6tflIFsvDp8Pyop7xNmGg,33146
151
- nabu/pipeline/fullfield/processconfig.py,sha256=9KSvj5y-PmiXAf_nTIjCn6938fMyUqArVM16-2pxHbc,38461
150
+ nabu/pipeline/fullfield/processconfig.py,sha256=skNF8z7bV0-dw8xJUUNsrR2hSnmBYG1fnwIpyIS2Jfs,38393
152
151
  nabu/pipeline/fullfield/reconstruction.py,sha256=cljRyxD8rvZ5qDws_5AwChi7P-5T_0SSXsGkYUGOVb8,38006
153
152
  nabu/pipeline/helical/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
154
153
  nabu/pipeline/helical/dataset_validator.py,sha256=HdKjUSj3PIpJb1dKSzJg8s4zXbAnMPWaPn8kvp_xQEs,657
@@ -169,7 +168,7 @@ nabu/pipeline/tests/test_estimators.py,sha256=fYSc5ZA9j7e--AC9D4es7cSQ8-e0FsYq4I
169
168
  nabu/pipeline/xrdct/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
170
169
  nabu/preproc/__init__.py,sha256=dKxvZvWZXjKS3iPRaSXiUeM2dNGIOyTlirq5pdAWY0Y,284
171
170
  nabu/preproc/alignment.py,sha256=PUw4YdpCmY6FVkUaosaT6LxFoNgPv7XHFy11Fhz1_6w,19
172
- nabu/preproc/ccd.py,sha256=QEe6c0bynAziE-r1obWLNRZ1i6xqpwlitT0eMN_r678,6977
171
+ nabu/preproc/ccd.py,sha256=LELLZcoJaae9V6zW2lXehyP54-xWuvvQ3_0OIxWrpos,6979
173
172
  nabu/preproc/ccd_cuda.py,sha256=IckZjk0fznVgX6VlBWZEURar_RqvMTN-g87Aj6Y8rJk,6093
174
173
  nabu/preproc/ctf.py,sha256=LEZT5fawEIIT3Qx0V0910RSv8aPLYuuHDrMzTYqyd5o,14981
175
174
  nabu/preproc/ctf_cuda.py,sha256=j6s8JOYQ7IVuu5HHAoGJhbTRW2zi7t5d6YrcAxIU0aQ,5268
@@ -177,7 +176,7 @@ nabu/preproc/distortion.py,sha256=XksQNrrSBfZS7mlvIdVEMZjw839ppQWP6AitTLcgfb0,33
177
176
  nabu/preproc/double_flatfield.py,sha256=WcYsNuotgQgm_KaioNa3OVI8rGfk3Wrn_YCW5v4mo4w,7895
178
177
  nabu/preproc/double_flatfield_cuda.py,sha256=lqgvZyeujdWJ5nF_GNRMQx7punjqA3SZ8K3IIyL3HDY,6197
179
178
  nabu/preproc/double_flatfield_variable_region.py,sha256=yiyvfGLFv3b93aKzHw84EQszPwQHfBv0PqtlQ8khvm4,2258
180
- nabu/preproc/flatfield.py,sha256=pjXDcICtRtErj3_s3eBMkytqj0JL2hwjnwTKoDbZFLk,30572
179
+ nabu/preproc/flatfield.py,sha256=Lgh_2MsszLshUotH-Y1RJj0qtplnASy81tuanuxPrdc,30552
181
180
  nabu/preproc/flatfield_cuda.py,sha256=Iiqv7bHa870DZOH68L19xiN1kG9I9JXuckFfA3khGtY,5482
182
181
  nabu/preproc/flatfield_variable_region.py,sha256=RVmSW515vgkHagjqotPNPUe97oQooHgdqkBn6hPH_2Q,3142
183
182
  nabu/preproc/phase.py,sha256=nRFhnHN_Bmmu5AHDcoO-Kt59sXYFSQaTljHZ5dlZiA0,13857
@@ -228,7 +227,6 @@ nabu/processing/tests/test_rotation.py,sha256=5O1yHthJfdoP-2loXob96j_V2IwI2eb8ro
228
227
  nabu/processing/tests/test_transpose.py,sha256=hTG17wTaB5Wv6twbW3ZFhBv6BYfqJY7DTQPoO0-KdkM,2760
229
228
  nabu/processing/tests/test_unsharp.py,sha256=R3ovbwDDp3ccy2A8t6CcUVELXRWkED5EnQdN2FQOfQM,4391
230
229
  nabu/reconstruction/__init__.py,sha256=EmKVvx_-FJvzJngG4ielIC7FhMCpI1Waaflg_lF44tk,163
231
- nabu/reconstruction/astra.py,sha256=qnFYabU-Bzgys8hXjIBcwO2NazrvhNXUYFIkMHc6BmM,10444
232
230
  nabu/reconstruction/cone.py,sha256=tSjaMDHeFV-h_IFbxUqSbhqlWmvlBcJQ8u89Y9Q9gg8,20559
233
231
  nabu/reconstruction/fbp.py,sha256=ptHcQsZTxgMFa9PhFJeTzDekibWR-P1BUj2SvRrk770,5684
234
232
  nabu/reconstruction/fbp_base.py,sha256=usd49ctQMI5w6uU5xn8qBsN7gI95iU9a3jRZgSPmOJk,18653
@@ -319,9 +317,9 @@ nabu/thirdparty/pore3d_deringer_munch.py,sha256=o4bisnFc-wMjuohWBT8wgWmfNehPQGtC
319
317
  nabu/thirdparty/tomocupy_remove_stripe.py,sha256=Khe4zFf0kRzu65Yxnvq58gt1ljOztqJGdMDhVAiM7lM,24363
320
318
  nabu/thirdparty/tomopy_phase.py,sha256=hK4oPpkogLOhv23XzzEXQY2u3r8fJvASY_bINVs6ERE,8634
321
319
  nabu/thirdparty/tomwer_load_flats_darks.py,sha256=ZNoVAinUb_wGYbfvs_4BVnWsjsQmNxSvCh1bWhR2WWg,5611
322
- nabu-2025.1.0rc2.dist-info/licenses/LICENSE,sha256=1eAIPSnEsnSFNUODnLtNtQTs76exG3ZxJ1DJR6zoUBA,1066
323
- nabu-2025.1.0rc2.dist-info/METADATA,sha256=zqtkSzfnyFPWwbEJEZmBJggv2U3P7UZhgMJDWnzl5LE,4274
324
- nabu-2025.1.0rc2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
325
- nabu-2025.1.0rc2.dist-info/entry_points.txt,sha256=YxzCY5CNQ1XHrIGbRKg-BgC1Jy7QaCITdITpyhhxpZU,1338
326
- nabu-2025.1.0rc2.dist-info/top_level.txt,sha256=fsm_N3eXLRZk2QXF9OSKPNDPFXOz8FAQjHh5avT3dok,9
327
- nabu-2025.1.0rc2.dist-info/RECORD,,
320
+ nabu-2025.1.0rc3.dist-info/licenses/LICENSE,sha256=1eAIPSnEsnSFNUODnLtNtQTs76exG3ZxJ1DJR6zoUBA,1066
321
+ nabu-2025.1.0rc3.dist-info/METADATA,sha256=YmXboCie2GZY8Om4wco2-8--nuhCJnhMq99FXIYKSfE,4274
322
+ nabu-2025.1.0rc3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
323
+ nabu-2025.1.0rc3.dist-info/entry_points.txt,sha256=YxzCY5CNQ1XHrIGbRKg-BgC1Jy7QaCITdITpyhhxpZU,1338
324
+ nabu-2025.1.0rc3.dist-info/top_level.txt,sha256=fsm_N3eXLRZk2QXF9OSKPNDPFXOz8FAQjHh5avT3dok,9
325
+ nabu-2025.1.0rc3.dist-info/RECORD,,
doc/doc_config.py DELETED
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env python
2
-
3
- from nabu.resources.nabu_config import nabu_config
4
-
5
-
6
- def generate(file_):
7
- def write(content):
8
- print(content, file=file_)
9
- for section, values in nabu_config.items():
10
- if section == "about":
11
- continue
12
- write("## %s\n" % section)
13
- for key, val in values.items():
14
- if val["type"] == "unsupported":
15
- continue
16
- write(val["help"] + "\n")
17
- write(
18
- "```ini\n%s = %s\n```"
19
- % (key, val["default"])
20
- )
21
-
22
-
23
-
24
- if __name__ == "__main__":
25
-
26
- import sys, os
27
- print(os.path.abspath(__file__))
28
- exit(0)
29
-
30
- fname = "/tmp/test.md"
31
- with open(fname, "w") as f:
32
- generate(f)
@@ -1,245 +0,0 @@
1
- # ruff: noqa
2
- try:
3
- import astra
4
-
5
- __have_astra__ = True
6
- except ImportError:
7
- __have_astra__ = False
8
- astra = None
9
-
10
-
11
- class AstraReconstructor:
12
- """
13
- Base class for reconstructors based on the Astra toolbox
14
- """
15
-
16
- default_extra_options = {
17
- "axis_correction": None,
18
- "clip_outer_circle": False,
19
- "scale_factor": None,
20
- "filter_cutoff": 1.0,
21
- "outer_circle_value": 0.0,
22
- }
23
-
24
- def __init__(
25
- self,
26
- sinos_shape,
27
- angles=None,
28
- volume_shape=None,
29
- rot_center=None,
30
- pixel_size=None,
31
- padding_mode="zeros",
32
- filter_name=None,
33
- slice_roi=None,
34
- cuda_options=None,
35
- extra_options=None,
36
- ):
37
- self._configure_extra_options(extra_options)
38
- self._init_cuda(cuda_options)
39
- self._set_sino_shape(sinos_shape)
40
- self._orig_prog_geom = None
41
- self._init_geometry(
42
- source_origin_dist,
43
- origin_detector_dist,
44
- pixel_size,
45
- angles,
46
- volume_shape,
47
- rot_center,
48
- relative_z_position,
49
- slice_roi,
50
- )
51
- self._init_fdk(padding_mode, filter_name)
52
- self._alg_id = None
53
- self._vol_id = None
54
- self._proj_id = None
55
-
56
- def _configure_extra_options(self, extra_options):
57
- self.extra_options = self.default_extra_options.copy()
58
- self.extra_options.update(extra_options or {})
59
-
60
- def _init_cuda(self, cuda_options):
61
- cuda_options = cuda_options or {}
62
- self.cuda = CudaProcessing(**cuda_options)
63
-
64
- def _set_sino_shape(self, sinos_shape):
65
- if len(sinos_shape) != 3:
66
- raise ValueError("Expected a 3D shape")
67
- self.sinos_shape = sinos_shape
68
- self.n_sinos, self.n_angles, self.prj_width = sinos_shape
69
-
70
- def _set_pixel_size(self, pixel_size):
71
- if pixel_size is None:
72
- det_spacing_y = det_spacing_x = 1
73
- elif np.iterable(pixel_size):
74
- det_spacing_y, det_spacing_x = pixel_size
75
- else:
76
- # assuming scalar
77
- det_spacing_y = det_spacing_x = pixel_size
78
- self._det_spacing_y = det_spacing_y
79
- self._det_spacing_x = det_spacing_x
80
-
81
- def _set_slice_roi(self, slice_roi):
82
- self.slice_roi = slice_roi
83
- self._vol_geom_n_x = self.n_x
84
- self._vol_geom_n_y = self.n_y
85
- self._crop_data = True
86
- if slice_roi is None:
87
- return
88
- start_x, end_x, start_y, end_y = slice_roi
89
- if roi_is_centered(self.volume_shape[1:], (slice(start_y, end_y), slice(start_x, end_x))):
90
- # Astra can only reconstruct subregion centered around the origin
91
- self._vol_geom_n_x = self.n_x - start_x * 2
92
- self._vol_geom_n_y = self.n_y - start_y * 2
93
- else:
94
- raise NotImplementedError(
95
- "Astra supports only slice_roi centered around origin (got slice_roi=%s with n_x=%d, n_y=%d)"
96
- % (str(slice_roi), self.n_x, self.n_y)
97
- )
98
-
99
- def _init_geometry(
100
- self,
101
- source_origin_dist,
102
- origin_detector_dist,
103
- pixel_size,
104
- angles,
105
- volume_shape,
106
- rot_center,
107
- relative_z_position,
108
- slice_roi,
109
- ):
110
- if angles is None:
111
- self.angles = np.linspace(0, 2 * np.pi, self.n_angles, endpoint=True)
112
- else:
113
- self.angles = angles
114
- if volume_shape is None:
115
- volume_shape = (self.sinos_shape[0], self.sinos_shape[2], self.sinos_shape[2])
116
- self.volume_shape = volume_shape
117
- self.n_z, self.n_y, self.n_x = self.volume_shape
118
- self.source_origin_dist = source_origin_dist
119
- self.origin_detector_dist = origin_detector_dist
120
- self.magnification = 1 + origin_detector_dist / source_origin_dist
121
- self._set_slice_roi(slice_roi)
122
- self.vol_geom = astra.create_vol_geom(self._vol_geom_n_y, self._vol_geom_n_x, self.n_z)
123
- self.vol_shape = astra.geom_size(self.vol_geom)
124
- self._cor_shift = 0.0
125
- self.rot_center = rot_center
126
- if rot_center is not None:
127
- self._cor_shift = (self.sinos_shape[-1] - 1) / 2.0 - rot_center
128
- self._set_pixel_size(pixel_size)
129
- self._axis_corrections = self.extra_options.get("axis_correction", None)
130
- self._create_astra_proj_geometry(relative_z_position)
131
-
132
- def _create_astra_proj_geometry(self, relative_z_position):
133
- # This object has to be re-created each time, because once the modifications below are done,
134
- # it is no more a "cone" geometry but a "cone_vec" geometry, and cannot be updated subsequently
135
- # (see astra/functions.py:271)
136
- self.proj_geom = astra.create_proj_geom(
137
- "cone",
138
- self._det_spacing_x,
139
- self._det_spacing_y,
140
- self.n_sinos,
141
- self.prj_width,
142
- self.angles,
143
- self.source_origin_dist,
144
- self.origin_detector_dist,
145
- )
146
- self.relative_z_position = relative_z_position or 0.0
147
- # This will turn the geometry of type "cone" into a geometry of type "cone_vec"
148
- if self._orig_prog_geom is None:
149
- self._orig_prog_geom = self.proj_geom
150
- self.proj_geom = astra.geom_postalignment(self.proj_geom, (self._cor_shift, 0))
151
- # (src, detector_center, u, v) = (srcX, srcY, srcZ, dX, dY, dZ, uX, uY, uZ, vX, vY, vZ)
152
- vecs = self.proj_geom["Vectors"]
153
-
154
- # To adapt the center of rotation:
155
- # dX = cor_shift * cos(theta) - origin_detector_dist * sin(theta)
156
- # dY = origin_detector_dist * cos(theta) + cor_shift * sin(theta)
157
- if self._axis_corrections is not None:
158
- # should we check that dX and dY match the above formulas ?
159
- cor_shifts = self._cor_shift + self._axis_corrections
160
- vecs[:, 3] = cor_shifts * np.cos(self.angles) - self.origin_detector_dist * np.sin(self.angles)
161
- vecs[:, 4] = self.origin_detector_dist * np.cos(self.angles) + cor_shifts * np.sin(self.angles)
162
-
163
- # To adapt the z position:
164
- # Component 2 of vecs is the z coordinate of the source, component 5 is the z component of the detector position
165
- # We need to re-create the same inclination of the cone beam, thus we need to keep the inclination of the two z positions.
166
- # The detector is centered on the rotation axis, thus moving it up or down, just moves it out of the reconstruction volume.
167
- # We can bring back the detector in the correct volume position, by applying a rigid translation of both the detector and the source.
168
- # The translation is exactly the amount that brought the detector up or down, but in the opposite direction.
169
- vecs[:, 2] = -self.relative_z_position
170
-
171
- def _set_output(self, volume):
172
- if volume is not None:
173
- expected_shape = self.vol_shape # if not (self._crop_data) else self._output_cropped_shape
174
- self.cuda.check_array(volume, expected_shape)
175
- self.cuda.set_array("output", volume)
176
- if volume is None:
177
- self.cuda.allocate_array("output", self.vol_shape)
178
- d_volume = self.cuda.get_array("output")
179
- z, y, x = d_volume.shape
180
- self._vol_link = astra.data3d.GPULink(d_volume.ptr, x, y, z, d_volume.strides[-2])
181
- self._vol_id = astra.data3d.link("-vol", self.vol_geom, self._vol_link)
182
-
183
- def _set_input(self, sinos):
184
- self.cuda.check_array(sinos, self.sinos_shape)
185
- self.cuda.set_array("sinos", sinos) # self.cuda.sinos is now a GPU array
186
- # TODO don't create new link/proj_id if ptr is the same ?
187
- # But it seems Astra modifies the input sinogram while doing FDK, so this might be not relevant
188
- d_sinos = self.cuda.get_array("sinos")
189
-
190
- # self._proj_data_link = astra.data3d.GPULink(d_sinos.ptr, self.prj_width, self.n_angles, self.n_z, sinos.strides[-2])
191
- self._proj_data_link = astra.data3d.GPULink(
192
- d_sinos.ptr, self.prj_width, self.n_angles, self.n_sinos, d_sinos.strides[-2]
193
- )
194
- self._proj_id = astra.data3d.link("-sino", self.proj_geom, self._proj_data_link)
195
-
196
- def _preprocess_data(self):
197
- d_sinos = self.cuda.sinos
198
- for i in range(d_sinos.shape[0]):
199
- self.sino_filter.filter_sino(d_sinos[i], output=d_sinos[i])
200
-
201
- def _update_reconstruction(self):
202
- cfg = astra.astra_dict("BP3D_CUDA")
203
- cfg["ReconstructionDataId"] = self._vol_id
204
- cfg["ProjectionDataId"] = self._proj_id
205
- if self._alg_id is not None:
206
- astra.algorithm.delete(self._alg_id)
207
- self._alg_id = astra.algorithm.create(cfg)
208
-
209
- def reconstruct(self, sinos, output=None, relative_z_position=None):
210
- """
211
- sinos: numpy.ndarray or pycuda.gpuarray
212
- Sinograms, with shape (n_sinograms, n_angles, width)
213
- output: pycuda.gpuarray, optional
214
- Output array. If not provided, a new numpy array is returned
215
- relative_z_position: int, optional
216
- Position of the central slice of the slab, with respect to the full stack of slices.
217
- By default it is set to zero, meaning that the current slab is assumed in the middle of the stack
218
- """
219
- self._create_astra_proj_geometry(relative_z_position)
220
- self._set_input(sinos)
221
- self._set_output(output)
222
- self._preprocess_data()
223
- self._update_reconstruction()
224
- astra.algorithm.run(self._alg_id)
225
- #
226
- # NB: Could also be done with
227
- # from astra.experimental import direct_BP3D
228
- # projector_id = astra.create_projector("cuda3d", self.proj_geom, self.vol_geom, options=None)
229
- # direct_BP3D(projector_id, self._vol_link, self._proj_data_link)
230
- #
231
- result = self.cuda.get_array("output")
232
- if output is None:
233
- result = result.get()
234
- if self.extra_options.get("scale_factor", None) is not None:
235
- result *= np.float32(self.extra_options["scale_factor"]) # in-place for pycuda
236
- self.cuda.recover_arrays_references(["sinos", "output"])
237
- return result
238
-
239
- def __del__(self):
240
- if getattr(self, "_alg_id", None) is not None:
241
- astra.algorithm.delete(self._alg_id)
242
- if getattr(self, "_vol_id", None) is not None:
243
- astra.data3d.delete(self._vol_id)
244
- if getattr(self, "_proj_id", None) is not None:
245
- astra.data3d.delete(self._proj_id)