nabu 2024.2.0rc4__py3-none-any.whl → 2024.2.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.
nabu/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "2024.2.0-rc4"
1
+ __version__ = "2024.2.1"
2
2
  __nabu_modules__ = [
3
3
  "app",
4
4
  "cuda",
nabu/app/cli_configs.py CHANGED
@@ -37,7 +37,7 @@ BootstrapConfig = {
37
37
  "default": "",
38
38
  },
39
39
  "template": {
40
- "help": "Use a template configuration file. Available are: id19_pag, id16_holo, id16_ctf. You can also define your own templates via the NABU_TEMPLATES_PATH environment variable.",
40
+ "help": "Use a template configuration file. Available are: id19_pag, id16_holo, id16_ctf, id16a_fluo, bm05_pag. You can also define your own templates via the NABU_TEMPLATES_PATH environment variable.",
41
41
  "default": "",
42
42
  },
43
43
  "helical": {"help": "Prepare configuration file for helical", "default": 0, "required": False, "type": int},
File without changes
@@ -465,7 +465,7 @@ class ProcessConfig(ProcessConfigBase):
465
465
  if self.get_radios_rotation_mode() == "chunk":
466
466
  tasks.append("tilt_correction")
467
467
  options["tilt_correction"] = {
468
- "angle": nabu_config["preproc"]["tilt_correction"] or dataset_info.detector_tilt,
468
+ "angle": dataset_info.detector_tilt,
469
469
  "center": nabu_config["preproc"]["rotate_projections_center"],
470
470
  "mode": "chunk",
471
471
  }
@@ -513,7 +513,7 @@ class ProcessConfig(ProcessConfigBase):
513
513
  if self.get_radios_rotation_mode() == "full":
514
514
  tasks.append("tilt_correction")
515
515
  options["tilt_correction"] = {
516
- "angle": nabu_config["preproc"]["tilt_correction"] or dataset_info.detector_tilt,
516
+ "angle": dataset_info.detector_tilt,
517
517
  "center": nabu_config["preproc"]["rotate_projections_center"],
518
518
  "mode": "full",
519
519
  }
@@ -253,7 +253,7 @@ class FullFieldReconstructor:
253
253
  if self.process_config.processing_options.get("phase", {}).get("method", None) == "CTF":
254
254
  force_grouped_mode = True
255
255
  msg = "CTF phase retrieval needs to process full radios"
256
- if self.process_config.processing_options.get("tilt_correction", {}).get("angle", 0) > 15:
256
+ if (self.process_config.dataset_info.detector_tilt or 0) > 15:
257
257
  force_grouped_mode = True
258
258
  msg = "Radios rotation with a large angle needs to process full radios"
259
259
  if self.process_config.resume_from_step == "sinogram" and force_grouped_mode:
@@ -35,12 +35,10 @@ def get_frame_possible_urls(dataset_info, user_dir, output_dir):
35
35
  else:
36
36
  dataurl_default_template = h5scan.REDUCED_DARKS_DATAURLS[0]
37
37
 
38
- rel_file_path = dataurl_default_template.file_path().format(
39
- scan_prefix=dataset_info.dataset_scanner.get_dataset_basename()
40
- )
38
+ rel_file_path = dataurl_default_template.file_path().format(scan_prefix=h5scan.get_dataset_basename())
41
39
  return DataUrl(
42
40
  file_path=os.path.join(dirname, rel_file_path),
43
- data_path=dataurl_default_template.data_path(),
41
+ data_path=dataurl_default_template.data_path().format(entry=h5scan.entry, index="{index}"),
44
42
  data_slice=dataurl_default_template.data_slice(), # not sure if needed
45
43
  scheme="silx",
46
44
  )
@@ -144,9 +142,11 @@ def data_url_exists(data_url):
144
142
  """
145
143
  if not (os.path.isfile(data_url.file_path())):
146
144
  return False
145
+ group_exists = False
147
146
  with HDF5File(data_url.file_path(), "r") as f:
148
- path_exists = f.get(data_url.data_path(), default=None) is not None
149
- return path_exists
147
+ data_path_without_index = data_url.data_path().split("{")[0]
148
+ group_exists = f.get(data_path_without_index, default=None) is not None
149
+ return group_exists
150
150
 
151
151
 
152
152
  # pylint: disable=E1136
@@ -0,0 +1,10 @@
1
+ import pytest
2
+ from nabu.utils import list_match_queries
3
+
4
+
5
+ def test_list_match_queries():
6
+
7
+ # entry0000 .... entry0099
8
+ avail = ["entry%04d" % i for i in range(100)]
9
+ query = "entry0000"
10
+ list_match_queries()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nabu
3
- Version: 2024.2.0rc4
3
+ Version: 2024.2.1
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>
@@ -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=NEQPS4U8T5nfg0_kumGk9YWMlO5RkFqOihedIBF9z_A,274
4
+ nabu/__init__.py,sha256=_crjpH1e06xe5ACe0WGTWJwi-ZGm59UWsB_3tUnYxlA,270
6
5
  nabu/tests.py,sha256=cew9OY2uTyncHI_HM32W8CP6B1GTGKaOW65XtMEqs7o,1417
7
6
  nabu/testutils.py,sha256=VkSL9tbY0XEH49Z5OjDFFhzkSxrCv4UIuvSVFgegSUY,7632
8
7
  nabu/utils.py,sha256=V1B_sD54XGNKn5pORa2yNCATyswOzybey3sv8BuIYWY,26355
@@ -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=Inr0_zRAtyeMTK1BKxGqoDf-Na0O33CICmQJYja06ug,2148
12
11
  nabu/app/cast_volume.py,sha256=mjINEIFrh2BVC8mPFO0cnzlFUOS3x5aqjFPGKsb3H-c,11264
13
- nabu/app/cli_configs.py,sha256=frcKu4Pp6380Gf2j0loP8OYqVRlTcjlLQBHe1mGJR_A,22254
12
+ nabu/app/cli_configs.py,sha256=EGKp7DrR48PAahZLJd09XAIAdm7Q5nOVSybztglhW_8,22276
14
13
  nabu/app/compare_volumes.py,sha256=Mu5O4uP-ANo-el-fE5PLvEq42BTk5FkrscaFRyQZdis,3341
15
14
  nabu/app/composite_cor.py,sha256=TjYiAtmY4o9lwNpkIEueTTNli72QN6jtR_zbtCeOJz4,5138
16
15
  nabu/app/correct_rot.py,sha256=K0UQz4l5caFvsSr1-1y5hZvt6e45NAH3qYOhzHm2mGc,2130
@@ -32,6 +31,7 @@ nabu/app/shrink_dataset.py,sha256=P9dorO0Q-gPAWgSHyZi3XQp4jkMTJacDYzNvJY4oh98,35
32
31
  nabu/app/stitching.py,sha256=T5nQVp7D6jNg86vMi8BCQANJJsKstvwItJWZDs05t64,4194
33
32
  nabu/app/utils.py,sha256=XUBRWDmth4i3BZHd27rfarFAUP7OEcsMeVmDJ6T4EXA,1178
34
33
  nabu/app/validator.py,sha256=IR-DcUV5h1Fc5CChBfBIaglrGpfKNICX7tGirAroMiw,3368
34
+ nabu/app/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
35
  nabu/app/tests/test_reduce_dark_flat.py,sha256=qD52JL6fgJh7UEeGLssmsmGkqPTL8YTu29Hj1Nk9Bjg,2725
36
36
  nabu/cuda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
37
  nabu/cuda/convolution.py,sha256=n8KsJ7IZdPOs_K5QZC6qblnOvIKYwxtdt03oNa0GiMU,241
@@ -143,8 +143,8 @@ nabu/pipeline/fullfield/chunked_cuda.py,sha256=Jdkk6ZIt3S6UZYbupHtSj2vrj3krWMcqR
143
143
  nabu/pipeline/fullfield/computations.py,sha256=AEp3qvwyY-l8-GzjH1E6kmcmU6OgDp6sB-mltq0Jnxg,9970
144
144
  nabu/pipeline/fullfield/dataset_validator.py,sha256=Iy6oOnXnBldDcg0ifm_zzrzMQ6YdkR_hkHFySZgxbno,2943
145
145
  nabu/pipeline/fullfield/nabu_config.py,sha256=rvHmCNHx2y-GKBidRWCAjJd0IynvolPTTmBqNoOSvEA,31877
146
- nabu/pipeline/fullfield/processconfig.py,sha256=SXEWU27xRYfTUyyczuJmn-0IA3A5EsvFpzK0Q47-3HE,36905
147
- nabu/pipeline/fullfield/reconstruction.py,sha256=nmJWXna6XODOu0GuufSnz3s6fLCZhZrkBUFHII8nudo,37450
146
+ nabu/pipeline/fullfield/processconfig.py,sha256=2eE9W0KjsHq8aSCXlczsISpWM9SMjWL03fN1RqZWyxg,36815
147
+ nabu/pipeline/fullfield/reconstruction.py,sha256=fMHKR8LnpQ2_asIO5bJB3pRixABrKLi53KzJuB83NZ4,37422
148
148
  nabu/pipeline/helical/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
149
149
  nabu/pipeline/helical/dataset_validator.py,sha256=0YQc0hdYdpaXznFaKmlj9SIu7mNs0xXMejcRkhOZHaI,640
150
150
  nabu/pipeline/helical/fbp.py,sha256=0fAz-Fb0Rn_FzellvcS2cy-Wvm-5dxEf494YFt4pLws,5845
@@ -221,7 +221,6 @@ nabu/processing/tests/test_rotation.py,sha256=vedRXV9RePJywBKoyBkGANP1dhZCjphbYO
221
221
  nabu/processing/tests/test_transpose.py,sha256=hTG17wTaB5Wv6twbW3ZFhBv6BYfqJY7DTQPoO0-KdkM,2760
222
222
  nabu/processing/tests/test_unsharp.py,sha256=R3ovbwDDp3ccy2A8t6CcUVELXRWkED5EnQdN2FQOfQM,4391
223
223
  nabu/reconstruction/__init__.py,sha256=EmKVvx_-FJvzJngG4ielIC7FhMCpI1Waaflg_lF44tk,163
224
- nabu/reconstruction/astra.py,sha256=qTAkUe6UGN5CRqS9ie-nDsvZTYrXBIjUl0JzPKQjkMg,10431
225
224
  nabu/reconstruction/cone.py,sha256=WObFcHvv7NkaZhUoC_xTlvl95f38AjsAJkePSOzngVk,18870
226
225
  nabu/reconstruction/fbp.py,sha256=uwEniGdEOn1atc9mTAHEDeF1y-ZqneifCKVr-ieHZss,5015
227
226
  nabu/reconstruction/fbp_base.py,sha256=DwZCilPXgGMRPV8_XfkWiaXUzWFM8rNBa8IyMdy5nno,17092
@@ -254,7 +253,7 @@ nabu/resources/cor.py,sha256=-mcrTbj3G7o4PP5E_gIRo2j6_-ADmMkkOc_0CyQv84c,170
254
253
  nabu/resources/dataset_analyzer.py,sha256=e3AqYR9ORW9Q03mGYCiC66nXld-X0LPnx9E8X3zFIGU,18568
255
254
  nabu/resources/gpu.py,sha256=GgpMb5umRQAUsEDEAefb4wSA5qm4JSMhkWmCEpW3X9g,5702
256
255
  nabu/resources/logger.py,sha256=-lOzhN_sU4R3BIfC69aMj2O8S_ocsvXsmwkhWlcxVEc,3758
257
- nabu/resources/nxflatfield.py,sha256=XlhLYj1TmSQ4s36W48kn0lNTvqXlFCuZxKHfTveltow,9225
256
+ nabu/resources/nxflatfield.py,sha256=FhPqiXe6ZKu5eGI6aVfyTgcHhZF9kQUNX0cOxDPD73k,9324
258
257
  nabu/resources/utils.py,sha256=LtOWEYneEzz0mDIpUWM23v9ILJ8FM0YFaVG3fFVc7OU,5725
259
258
  nabu/resources/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
260
259
  nabu/resources/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -264,6 +263,7 @@ nabu/resources/templates/id16_holo.conf,sha256=sDd_rEJGZjOGVAsGub5sT2arfXDnc_sxy
264
263
  nabu/resources/templates/id16a_fluo.conf,sha256=Nz1etzO2fSwksi7CThWJ5T1kZEdyBe8rMO7puNJ93Hc,542
265
264
  nabu/resources/templates/id19_pag.conf,sha256=u4fFPEBprzOW9_5_ChkIgowQcYpLhjmA8Gwm5XgC4Jc,384
266
265
  nabu/resources/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
266
+ nabu/resources/tests/test_extract.py,sha256=pDFvgwPNH4n-UjhJibRH2vTkjDWYF2wSImUtfNq1ITo,220
267
267
  nabu/resources/tests/test_nxflatfield.py,sha256=XRGbYwqJv0NYAVQnAB224TwTZP_W2Bs3-yu0zQnDzEM,4179
268
268
  nabu/resources/tests/test_units.py,sha256=F2jFTck-1UwYET1MwTtX6ntzYUosfwOJkugSencGgz8,2155
269
269
  nabu/stitching/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -311,9 +311,9 @@ nabu/thirdparty/pore3d_deringer_munch.py,sha256=o4bisnFc-wMjuohWBT8wgWmfNehPQGtC
311
311
  nabu/thirdparty/tomocupy_remove_stripe.py,sha256=Khe4zFf0kRzu65Yxnvq58gt1ljOztqJGdMDhVAiM7lM,24363
312
312
  nabu/thirdparty/tomopy_phase.py,sha256=hK4oPpkogLOhv23XzzEXQY2u3r8fJvASY_bINVs6ERE,8634
313
313
  nabu/thirdparty/tomwer_load_flats_darks.py,sha256=ZNoVAinUb_wGYbfvs_4BVnWsjsQmNxSvCh1bWhR2WWg,5611
314
- nabu-2024.2.0rc4.dist-info/LICENSE,sha256=1eAIPSnEsnSFNUODnLtNtQTs76exG3ZxJ1DJR6zoUBA,1066
315
- nabu-2024.2.0rc4.dist-info/METADATA,sha256=X82wyEoBnquYyUlKh6UBebcpBLAS9ieXX7EETWAe068,5541
316
- nabu-2024.2.0rc4.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
317
- nabu-2024.2.0rc4.dist-info/entry_points.txt,sha256=cJKGkBeykVL7uK3E4R0RLRqMXifTL2qdO573syPAvJc,1288
318
- nabu-2024.2.0rc4.dist-info/top_level.txt,sha256=fsm_N3eXLRZk2QXF9OSKPNDPFXOz8FAQjHh5avT3dok,9
319
- nabu-2024.2.0rc4.dist-info/RECORD,,
314
+ nabu-2024.2.1.dist-info/LICENSE,sha256=1eAIPSnEsnSFNUODnLtNtQTs76exG3ZxJ1DJR6zoUBA,1066
315
+ nabu-2024.2.1.dist-info/METADATA,sha256=XlEefB-apFg-XrbRJ-uOM18VdoqY-MXyiqO77-l3_m4,5538
316
+ nabu-2024.2.1.dist-info/WHEEL,sha256=5sUXSg9e4bi7lTLOHcm6QEYwO5TIF1TNbTSVFVjcJcc,92
317
+ nabu-2024.2.1.dist-info/entry_points.txt,sha256=cJKGkBeykVL7uK3E4R0RLRqMXifTL2qdO573syPAvJc,1288
318
+ nabu-2024.2.1.dist-info/top_level.txt,sha256=fsm_N3eXLRZk2QXF9OSKPNDPFXOz8FAQjHh5avT3dok,9
319
+ nabu-2024.2.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: bdist_wheel (0.41.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
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,244 +0,0 @@
1
- try:
2
- import astra
3
-
4
- __have_astra__ = True
5
- except ImportError:
6
- __have_astra__ = False
7
- astra = None
8
-
9
-
10
- class AstraReconstructor:
11
- """
12
- Base class for reconstructors based on the Astra toolbox
13
- """
14
-
15
- default_extra_options = {
16
- "axis_correction": None,
17
- "clip_outer_circle": False,
18
- "scale_factor": None,
19
- "filter_cutoff": 1.0,
20
- "outer_circle_value": 0.0,
21
- }
22
-
23
- def __init__(
24
- self,
25
- sinos_shape,
26
- angles=None,
27
- volume_shape=None,
28
- rot_center=None,
29
- pixel_size=None,
30
- padding_mode="zeros",
31
- filter_name=None,
32
- slice_roi=None,
33
- cuda_options=None,
34
- extra_options=None,
35
- ):
36
- self._configure_extra_options(extra_options)
37
- self._init_cuda(cuda_options)
38
- self._set_sino_shape(sinos_shape)
39
- self._orig_prog_geom = None
40
- self._init_geometry(
41
- source_origin_dist,
42
- origin_detector_dist,
43
- pixel_size,
44
- angles,
45
- volume_shape,
46
- rot_center,
47
- relative_z_position,
48
- slice_roi,
49
- )
50
- self._init_fdk(padding_mode, filter_name)
51
- self._alg_id = None
52
- self._vol_id = None
53
- self._proj_id = None
54
-
55
- def _configure_extra_options(self, extra_options):
56
- self.extra_options = self.default_extra_options.copy()
57
- self.extra_options.update(extra_options or {})
58
-
59
- def _init_cuda(self, cuda_options):
60
- cuda_options = cuda_options or {}
61
- self.cuda = CudaProcessing(**cuda_options)
62
-
63
- def _set_sino_shape(self, sinos_shape):
64
- if len(sinos_shape) != 3:
65
- raise ValueError("Expected a 3D shape")
66
- self.sinos_shape = sinos_shape
67
- self.n_sinos, self.n_angles, self.prj_width = sinos_shape
68
-
69
- def _set_pixel_size(self, pixel_size):
70
- if pixel_size is None:
71
- det_spacing_y = det_spacing_x = 1
72
- elif np.iterable(pixel_size):
73
- det_spacing_y, det_spacing_x = pixel_size
74
- else:
75
- # assuming scalar
76
- det_spacing_y = det_spacing_x = pixel_size
77
- self._det_spacing_y = det_spacing_y
78
- self._det_spacing_x = det_spacing_x
79
-
80
- def _set_slice_roi(self, slice_roi):
81
- self.slice_roi = slice_roi
82
- self._vol_geom_n_x = self.n_x
83
- self._vol_geom_n_y = self.n_y
84
- self._crop_data = True
85
- if slice_roi is None:
86
- return
87
- start_x, end_x, start_y, end_y = slice_roi
88
- if roi_is_centered(self.volume_shape[1:], (slice(start_y, end_y), slice(start_x, end_x))):
89
- # Astra can only reconstruct subregion centered around the origin
90
- self._vol_geom_n_x = self.n_x - start_x * 2
91
- self._vol_geom_n_y = self.n_y - start_y * 2
92
- else:
93
- raise NotImplementedError(
94
- "Astra supports only slice_roi centered around origin (got slice_roi=%s with n_x=%d, n_y=%d)"
95
- % (str(slice_roi), self.n_x, self.n_y)
96
- )
97
-
98
- def _init_geometry(
99
- self,
100
- source_origin_dist,
101
- origin_detector_dist,
102
- pixel_size,
103
- angles,
104
- volume_shape,
105
- rot_center,
106
- relative_z_position,
107
- slice_roi,
108
- ):
109
- if angles is None:
110
- self.angles = np.linspace(0, 2 * np.pi, self.n_angles, endpoint=True)
111
- else:
112
- self.angles = angles
113
- if volume_shape is None:
114
- volume_shape = (self.sinos_shape[0], self.sinos_shape[2], self.sinos_shape[2])
115
- self.volume_shape = volume_shape
116
- self.n_z, self.n_y, self.n_x = self.volume_shape
117
- self.source_origin_dist = source_origin_dist
118
- self.origin_detector_dist = origin_detector_dist
119
- self.magnification = 1 + origin_detector_dist / source_origin_dist
120
- self._set_slice_roi(slice_roi)
121
- self.vol_geom = astra.create_vol_geom(self._vol_geom_n_y, self._vol_geom_n_x, self.n_z)
122
- self.vol_shape = astra.geom_size(self.vol_geom)
123
- self._cor_shift = 0.0
124
- self.rot_center = rot_center
125
- if rot_center is not None:
126
- self._cor_shift = (self.sinos_shape[-1] - 1) / 2.0 - rot_center
127
- self._set_pixel_size(pixel_size)
128
- self._axis_corrections = self.extra_options.get("axis_correction", None)
129
- self._create_astra_proj_geometry(relative_z_position)
130
-
131
- def _create_astra_proj_geometry(self, relative_z_position):
132
- # This object has to be re-created each time, because once the modifications below are done,
133
- # it is no more a "cone" geometry but a "cone_vec" geometry, and cannot be updated subsequently
134
- # (see astra/functions.py:271)
135
- self.proj_geom = astra.create_proj_geom(
136
- "cone",
137
- self._det_spacing_x,
138
- self._det_spacing_y,
139
- self.n_sinos,
140
- self.prj_width,
141
- self.angles,
142
- self.source_origin_dist,
143
- self.origin_detector_dist,
144
- )
145
- self.relative_z_position = relative_z_position or 0.0
146
- # This will turn the geometry of type "cone" into a geometry of type "cone_vec"
147
- if self._orig_prog_geom is None:
148
- self._orig_prog_geom = self.proj_geom
149
- self.proj_geom = astra.geom_postalignment(self.proj_geom, (self._cor_shift, 0))
150
- # (src, detector_center, u, v) = (srcX, srcY, srcZ, dX, dY, dZ, uX, uY, uZ, vX, vY, vZ)
151
- vecs = self.proj_geom["Vectors"]
152
-
153
- # To adapt the center of rotation:
154
- # dX = cor_shift * cos(theta) - origin_detector_dist * sin(theta)
155
- # dY = origin_detector_dist * cos(theta) + cor_shift * sin(theta)
156
- if self._axis_corrections is not None:
157
- # should we check that dX and dY match the above formulas ?
158
- cor_shifts = self._cor_shift + self._axis_corrections
159
- vecs[:, 3] = cor_shifts * np.cos(self.angles) - self.origin_detector_dist * np.sin(self.angles)
160
- vecs[:, 4] = self.origin_detector_dist * np.cos(self.angles) + cor_shifts * np.sin(self.angles)
161
-
162
- # To adapt the z position:
163
- # Component 2 of vecs is the z coordinate of the source, component 5 is the z component of the detector position
164
- # We need to re-create the same inclination of the cone beam, thus we need to keep the inclination of the two z positions.
165
- # The detector is centered on the rotation axis, thus moving it up or down, just moves it out of the reconstruction volume.
166
- # We can bring back the detector in the correct volume position, by applying a rigid translation of both the detector and the source.
167
- # The translation is exactly the amount that brought the detector up or down, but in the opposite direction.
168
- vecs[:, 2] = -self.relative_z_position
169
-
170
- def _set_output(self, volume):
171
- if volume is not None:
172
- expected_shape = self.vol_shape # if not (self._crop_data) else self._output_cropped_shape
173
- self.cuda.check_array(volume, expected_shape)
174
- self.cuda.set_array("output", volume)
175
- if volume is None:
176
- self.cuda.allocate_array("output", self.vol_shape)
177
- d_volume = self.cuda.get_array("output")
178
- z, y, x = d_volume.shape
179
- self._vol_link = astra.data3d.GPULink(d_volume.ptr, x, y, z, d_volume.strides[-2])
180
- self._vol_id = astra.data3d.link("-vol", self.vol_geom, self._vol_link)
181
-
182
- def _set_input(self, sinos):
183
- self.cuda.check_array(sinos, self.sinos_shape)
184
- self.cuda.set_array("sinos", sinos) # self.cuda.sinos is now a GPU array
185
- # TODO don't create new link/proj_id if ptr is the same ?
186
- # But it seems Astra modifies the input sinogram while doing FDK, so this might be not relevant
187
- d_sinos = self.cuda.get_array("sinos")
188
-
189
- # self._proj_data_link = astra.data3d.GPULink(d_sinos.ptr, self.prj_width, self.n_angles, self.n_z, sinos.strides[-2])
190
- self._proj_data_link = astra.data3d.GPULink(
191
- d_sinos.ptr, self.prj_width, self.n_angles, self.n_sinos, d_sinos.strides[-2]
192
- )
193
- self._proj_id = astra.data3d.link("-sino", self.proj_geom, self._proj_data_link)
194
-
195
- def _preprocess_data(self):
196
- d_sinos = self.cuda.sinos
197
- for i in range(d_sinos.shape[0]):
198
- self.sino_filter.filter_sino(d_sinos[i], output=d_sinos[i])
199
-
200
- def _update_reconstruction(self):
201
- cfg = astra.astra_dict("BP3D_CUDA")
202
- cfg["ReconstructionDataId"] = self._vol_id
203
- cfg["ProjectionDataId"] = self._proj_id
204
- if self._alg_id is not None:
205
- astra.algorithm.delete(self._alg_id)
206
- self._alg_id = astra.algorithm.create(cfg)
207
-
208
- def reconstruct(self, sinos, output=None, relative_z_position=None):
209
- """
210
- sinos: numpy.ndarray or pycuda.gpuarray
211
- Sinograms, with shape (n_sinograms, n_angles, width)
212
- output: pycuda.gpuarray, optional
213
- Output array. If not provided, a new numpy array is returned
214
- relative_z_position: int, optional
215
- Position of the central slice of the slab, with respect to the full stack of slices.
216
- By default it is set to zero, meaning that the current slab is assumed in the middle of the stack
217
- """
218
- self._create_astra_proj_geometry(relative_z_position)
219
- self._set_input(sinos)
220
- self._set_output(output)
221
- self._preprocess_data()
222
- self._update_reconstruction()
223
- astra.algorithm.run(self._alg_id)
224
- #
225
- # NB: Could also be done with
226
- # from astra.experimental import direct_BP3D
227
- # projector_id = astra.create_projector("cuda3d", self.proj_geom, self.vol_geom, options=None)
228
- # direct_BP3D(projector_id, self._vol_link, self._proj_data_link)
229
- #
230
- result = self.cuda.get_array("output")
231
- if output is None:
232
- result = result.get()
233
- if self.extra_options.get("scale_factor", None) is not None:
234
- result *= np.float32(self.extra_options["scale_factor"]) # in-place for pycuda
235
- self.cuda.recover_arrays_references(["sinos", "output"])
236
- return result
237
-
238
- def __del__(self):
239
- if getattr(self, "_alg_id", None) is not None:
240
- astra.algorithm.delete(self._alg_id)
241
- if getattr(self, "_vol_id", None) is not None:
242
- astra.data3d.delete(self._vol_id)
243
- if getattr(self, "_proj_id", None) is not None:
244
- astra.data3d.delete(self._proj_id)