simind-python-connector 2.0.0__py3-none-any.whl → 3.0.0__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.
- simind_python_connector/__init__.py +3 -3
- simind_python_connector/builders/_native.py +86 -0
- simind_python_connector/builders/acquisition_builder.py +21 -81
- simind_python_connector/builders/image_builder.py +13 -72
- simind_python_connector/configs/__init__.py +10 -4
- simind_python_connector/connectors/__init__.py +0 -2
- simind_python_connector/connectors/_native_adaptor.py +354 -0
- simind_python_connector/connectors/python_connector.py +584 -61
- simind_python_connector/connectors/pytomography_adaptor.py +26 -23
- simind_python_connector/connectors/sirf_adaptor.py +21 -145
- simind_python_connector/connectors/stir_adaptor.py +23 -145
- simind_python_connector/converters/__init__.py +2 -2
- simind_python_connector/converters/attenuation.py +42 -48
- simind_python_connector/converters/simind_to_stir.py +16 -328
- simind_python_connector/core/config.py +65 -25
- simind_python_connector/core/executor.py +42 -50
- simind_python_connector/core/types.py +5 -24
- simind_python_connector/data/__init__.py +3 -3
- simind_python_connector/data/bone.atn +178 -187
- simind_python_connector/data/h2o.atn +84 -92
- simind_python_connector/normalisation.py +90 -0
- simind_python_connector/phantoms.py +386 -0
- simind_python_connector/recon/__init__.py +41 -0
- simind_python_connector/recon/cil.py +185 -0
- simind_python_connector/recon/corrections.py +108 -0
- simind_python_connector/recon/diagnostics.py +41 -0
- simind_python_connector/recon/osem.py +59 -0
- simind_python_connector/recon/projector.py +112 -0
- simind_python_connector/recon/updates.py +88 -0
- simind_python_connector/utils/__init__.py +8 -83
- simind_python_connector/utils/interfile.py +659 -0
- simind_python_connector/utils/simind_utils.py +4 -32
- {simind_python_connector-2.0.0.dist-info → simind_python_connector-3.0.0.dist-info}/METADATA +10 -5
- simind_python_connector-3.0.0.dist-info/RECORD +46 -0
- simind_python_connector/backends/__init__.py +0 -487
- simind_python_connector/backends/base.py +0 -387
- simind_python_connector/backends/sirf_backend.py +0 -309
- simind_python_connector/backends/stir_backend.py +0 -395
- simind_python_connector/connectors/_spacing.py +0 -75
- simind_python_connector/converters/dicom_to_stir.py +0 -3
- simind_python_connector/utils/backend_access.py +0 -121
- simind_python_connector/utils/import_helpers.py +0 -78
- simind_python_connector/utils/interfile_numpy.py +0 -205
- simind_python_connector/utils/interfile_parser.py +0 -177
- simind_python_connector/utils/io_utils.py +0 -14
- simind_python_connector/utils/sirf_stir_utils.py +0 -194
- simind_python_connector/utils/stir_utils.py +0 -490
- simind_python_connector-2.0.0.dist-info/RECORD +0 -47
- {simind_python_connector-2.0.0.dist-info → simind_python_connector-3.0.0.dist-info}/WHEEL +0 -0
- {simind_python_connector-2.0.0.dist-info → simind_python_connector-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {simind_python_connector-2.0.0.dist-info → simind_python_connector-3.0.0.dist-info}/top_level.txt +0 -0
|
@@ -14,7 +14,7 @@ for _dist_name in ("simind-python-connector", __name__):
|
|
|
14
14
|
except _meta.PackageNotFoundError:
|
|
15
15
|
continue
|
|
16
16
|
else: # editable / source checkout
|
|
17
|
-
__version__ = "
|
|
17
|
+
__version__ = "3.0.0"
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def __getattr__(name: str) -> Any:
|
|
@@ -25,6 +25,7 @@ def __getattr__(name: str) -> Any:
|
|
|
25
25
|
"converters",
|
|
26
26
|
"core",
|
|
27
27
|
"data",
|
|
28
|
+
"normalisation",
|
|
28
29
|
"utils",
|
|
29
30
|
}:
|
|
30
31
|
mod = importlib.import_module(f".{name}", __name__)
|
|
@@ -37,7 +38,6 @@ def __getattr__(name: str) -> Any:
|
|
|
37
38
|
return obj
|
|
38
39
|
elif name in {
|
|
39
40
|
"BaseConnector",
|
|
40
|
-
"NumpyConnector",
|
|
41
41
|
"PyTomographySimindAdaptor",
|
|
42
42
|
"ProjectionResult",
|
|
43
43
|
"RuntimeOperator",
|
|
@@ -54,7 +54,6 @@ def __getattr__(name: str) -> Any:
|
|
|
54
54
|
|
|
55
55
|
__all__ = [
|
|
56
56
|
"BaseConnector",
|
|
57
|
-
"NumpyConnector",
|
|
58
57
|
"ProjectionResult",
|
|
59
58
|
"PyTomographySimindAdaptor",
|
|
60
59
|
"RuntimeOperator",
|
|
@@ -68,5 +67,6 @@ __all__ = [
|
|
|
68
67
|
"converters",
|
|
69
68
|
"core",
|
|
70
69
|
"data",
|
|
70
|
+
"normalisation",
|
|
71
71
|
"utils",
|
|
72
72
|
]
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Load SIRF or STIR objects for the builders.
|
|
2
|
+
|
|
3
|
+
Backends are imported inside each function so importing the builders never
|
|
4
|
+
imports SIRF or STIR.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import importlib
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def resolve_backend(backend: Optional[str]) -> str:
|
|
16
|
+
"""Return "sirf" or "stir". None picks SIRF if importable, else STIR."""
|
|
17
|
+
if backend is None:
|
|
18
|
+
try:
|
|
19
|
+
importlib.import_module("sirf.STIR")
|
|
20
|
+
return "sirf"
|
|
21
|
+
except ImportError:
|
|
22
|
+
pass
|
|
23
|
+
try:
|
|
24
|
+
importlib.import_module("stir")
|
|
25
|
+
importlib.import_module("stirextra")
|
|
26
|
+
return "stir"
|
|
27
|
+
except ImportError:
|
|
28
|
+
raise ImportError(
|
|
29
|
+
"Neither SIRF nor STIR Python found. Install one of: "
|
|
30
|
+
"SIRF (sirf.STIR) or STIR Python (stir + stirextra)."
|
|
31
|
+
) from None
|
|
32
|
+
if backend == "sirf":
|
|
33
|
+
try:
|
|
34
|
+
importlib.import_module("sirf.STIR")
|
|
35
|
+
except ImportError as exc:
|
|
36
|
+
raise ImportError("SIRF is not available") from exc
|
|
37
|
+
return "sirf"
|
|
38
|
+
if backend == "stir":
|
|
39
|
+
try:
|
|
40
|
+
importlib.import_module("stir")
|
|
41
|
+
importlib.import_module("stirextra")
|
|
42
|
+
except ImportError as exc:
|
|
43
|
+
raise ImportError("STIR Python is not available") from exc
|
|
44
|
+
return "stir"
|
|
45
|
+
raise ValueError("backend must be one of: 'sirf', 'stir', or None")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def load_image(header_path: str, backend: Optional[str]):
|
|
49
|
+
"""Read an image header as a native SIRF or STIR image."""
|
|
50
|
+
if resolve_backend(backend) == "sirf":
|
|
51
|
+
import sirf.STIR
|
|
52
|
+
|
|
53
|
+
return sirf.STIR.ImageData(header_path)
|
|
54
|
+
import stir
|
|
55
|
+
|
|
56
|
+
return stir.FloatVoxelsOnCartesianGrid.read_from_file(header_path)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def load_acquisition(header_path: str, backend: Optional[str]):
|
|
60
|
+
"""Read projection data as native SIRF or in-memory STIR data.
|
|
61
|
+
|
|
62
|
+
STIR's ProjData reads lazily from disk, so it is copied into memory;
|
|
63
|
+
the builders may delete the files afterwards.
|
|
64
|
+
"""
|
|
65
|
+
if resolve_backend(backend) == "sirf":
|
|
66
|
+
import sirf.STIR
|
|
67
|
+
|
|
68
|
+
return sirf.STIR.AcquisitionData(header_path)
|
|
69
|
+
import stir
|
|
70
|
+
|
|
71
|
+
return stir.ProjDataInMemory(stir.ProjData.read_from_file(header_path))
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def refill_acquisition(acquisition, array: np.ndarray, header_path: str, backend: str):
|
|
75
|
+
"""Fill a copy of acquisition with array, write it to header_path, return it."""
|
|
76
|
+
if backend == "sirf":
|
|
77
|
+
filled = acquisition.clone()
|
|
78
|
+
filled.fill(array)
|
|
79
|
+
filled.write(header_path)
|
|
80
|
+
return filled
|
|
81
|
+
import stir
|
|
82
|
+
|
|
83
|
+
filled = stir.ProjDataInMemory(acquisition)
|
|
84
|
+
filled.fill(array.flat)
|
|
85
|
+
filled.write_to_file(header_path)
|
|
86
|
+
return filled
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import tempfile
|
|
3
4
|
import warnings
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import Literal, Optional
|
|
@@ -7,17 +8,7 @@ from typing import Literal, Optional
|
|
|
7
8
|
import numpy as np
|
|
8
9
|
import pydicom
|
|
9
10
|
|
|
10
|
-
from simind_python_connector.
|
|
11
|
-
|
|
12
|
-
# Conditional import for SIRF types
|
|
13
|
-
from simind_python_connector.utils.import_helpers import get_sirf_types
|
|
14
|
-
from simind_python_connector.utils.io_utils import temporary_directory
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
_, AcquisitionData, SIRF_AVAILABLE = get_sirf_types()
|
|
18
|
-
|
|
19
|
-
# Unpack interfaces needed by builder
|
|
20
|
-
create_acquisition_data = BACKENDS.factories.create_acquisition_data
|
|
11
|
+
from simind_python_connector.builders import _native
|
|
21
12
|
|
|
22
13
|
|
|
23
14
|
class STIRSPECTAcquisitionDataBuilder:
|
|
@@ -92,25 +83,25 @@ class STIRSPECTAcquisitionDataBuilder:
|
|
|
92
83
|
num_projections = int(self.header.get("!number of projections", 1))
|
|
93
84
|
if self.pixel_array is None:
|
|
94
85
|
self.pixel_array = np.zeros(
|
|
95
|
-
(1,
|
|
86
|
+
(1, matrix_size_2, num_projections, matrix_size_1), dtype=np.float32
|
|
96
87
|
)
|
|
97
88
|
else:
|
|
98
89
|
self.pixel_array = np.array(self.pixel_array, dtype=np.float32)
|
|
99
90
|
|
|
100
91
|
expected_shape = (
|
|
101
92
|
1,
|
|
102
|
-
matrix_size_1,
|
|
103
|
-
num_projections,
|
|
104
93
|
matrix_size_2,
|
|
94
|
+
num_projections,
|
|
95
|
+
matrix_size_1,
|
|
105
96
|
)
|
|
106
97
|
if self.pixel_array.shape != expected_shape:
|
|
107
98
|
raise ValueError(
|
|
108
99
|
f"pixel array shape {self.pixel_array.shape} does not match "
|
|
109
100
|
f"header dimensions {expected_shape} "
|
|
110
|
-
"(tof,
|
|
101
|
+
"(tof, axial, view, bin)"
|
|
111
102
|
)
|
|
112
103
|
|
|
113
|
-
def _write(base_path: Path
|
|
104
|
+
def _write(base_path: Path):
|
|
114
105
|
header_path = base_path.with_suffix(".hs")
|
|
115
106
|
raw_file_path = base_path.with_suffix(".s")
|
|
116
107
|
|
|
@@ -123,70 +114,17 @@ class STIRSPECTAcquisitionDataBuilder:
|
|
|
123
114
|
|
|
124
115
|
self.pixel_array.tofile(raw_file_path)
|
|
125
116
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
acqdata.write(str(header_path))
|
|
131
|
-
|
|
132
|
-
if cleanup:
|
|
133
|
-
header_path.unlink(missing_ok=True)
|
|
134
|
-
raw_file_path.unlink(missing_ok=True)
|
|
135
|
-
|
|
136
|
-
return self._unwrap_native(acqdata)
|
|
137
|
-
|
|
138
|
-
if output_path is None:
|
|
139
|
-
with temporary_directory() as tmp_dir:
|
|
140
|
-
return _write(Path(tmp_dir) / "spect_acq", cleanup=False)
|
|
141
|
-
|
|
142
|
-
return _write(Path(output_path), cleanup=False)
|
|
143
|
-
|
|
144
|
-
def _load_acquisition(self, header_path: str):
|
|
145
|
-
"""Load acquisition data with optional explicit backend selection."""
|
|
146
|
-
if BACKEND_AVAILABLE and create_acquisition_data is not None:
|
|
147
|
-
if (
|
|
148
|
-
self.backend is not None
|
|
149
|
-
and BACKENDS.detection.set_backend is not None
|
|
150
|
-
and BACKENDS.detection.get_backend is not None
|
|
151
|
-
):
|
|
152
|
-
previous_backend = None
|
|
153
|
-
try:
|
|
154
|
-
previous_backend = BACKENDS.detection.get_backend()
|
|
155
|
-
except Exception:
|
|
156
|
-
previous_backend = None
|
|
157
|
-
BACKENDS.detection.set_backend(self.backend)
|
|
158
|
-
try:
|
|
159
|
-
return create_acquisition_data(header_path)
|
|
160
|
-
finally:
|
|
161
|
-
if (
|
|
162
|
-
previous_backend is not None
|
|
163
|
-
and previous_backend != self.backend
|
|
164
|
-
):
|
|
165
|
-
try:
|
|
166
|
-
BACKENDS.detection.set_backend(previous_backend)
|
|
167
|
-
except Exception:
|
|
168
|
-
pass
|
|
169
|
-
return create_acquisition_data(header_path)
|
|
170
|
-
|
|
171
|
-
if self.backend == "stir":
|
|
172
|
-
raise ImportError(
|
|
173
|
-
"Requested STIR backend for acquisition loading, but backend wrappers "
|
|
174
|
-
"are unavailable."
|
|
117
|
+
backend = _native.resolve_backend(self.backend)
|
|
118
|
+
acqdata = _native.load_acquisition(str(header_path), backend)
|
|
119
|
+
return _native.refill_acquisition(
|
|
120
|
+
acqdata, self.pixel_array, str(header_path), backend
|
|
175
121
|
)
|
|
176
122
|
|
|
177
|
-
if
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
raise ImportError(
|
|
181
|
-
"Unable to load acquisition data: neither SIRF nor STIR Python "
|
|
182
|
-
"backends are available."
|
|
183
|
-
)
|
|
123
|
+
if output_path is None:
|
|
124
|
+
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
125
|
+
return _write(Path(tmp_dir) / "spect_acq")
|
|
184
126
|
|
|
185
|
-
|
|
186
|
-
def _unwrap_native(obj):
|
|
187
|
-
"""Return native backend object when a wrapper is provided."""
|
|
188
|
-
native = getattr(obj, "native_object", None)
|
|
189
|
-
return native if native is not None else obj
|
|
127
|
+
return _write(Path(output_path))
|
|
190
128
|
|
|
191
129
|
def build_multi_energy(self, output_path_base="temp", multiple_data_files=True):
|
|
192
130
|
"""
|
|
@@ -273,16 +211,18 @@ class STIRSPECTAcquisitionDataBuilder:
|
|
|
273
211
|
"Modality not found in DICOM. Retaining default '!imaging modality'."
|
|
274
212
|
)
|
|
275
213
|
try:
|
|
276
|
-
self.header["!matrix size [1]"] = str(ds.
|
|
277
|
-
self.header["!matrix size [2]"] = str(ds.
|
|
214
|
+
self.header["!matrix size [1]"] = str(ds.Columns)
|
|
215
|
+
self.header["!matrix size [2]"] = str(ds.Rows)
|
|
278
216
|
except AttributeError:
|
|
279
217
|
warnings.warn(
|
|
280
218
|
"Rows/Columns not found in DICOM. Retaining default matrix sizes."
|
|
281
219
|
)
|
|
282
220
|
try:
|
|
283
221
|
pixel_spacing = ds.PixelSpacing
|
|
284
|
-
|
|
285
|
-
|
|
222
|
+
# DICOM PixelSpacing is [row spacing, column spacing]; Interfile
|
|
223
|
+
# [1] is the column/bin axis and [2] the row/axial axis.
|
|
224
|
+
self.header["scaling factor (mm/pixel) [1]"] = str(pixel_spacing[1])
|
|
225
|
+
self.header["scaling factor (mm/pixel) [2]"] = str(pixel_spacing[0])
|
|
286
226
|
except AttributeError:
|
|
287
227
|
warnings.warn(
|
|
288
228
|
"PixelSpacing not found in DICOM. Retaining default scaling factors."
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import tempfile
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
from typing import Literal, Optional
|
|
5
6
|
|
|
6
7
|
import numpy as np
|
|
7
8
|
|
|
8
|
-
from simind_python_connector.
|
|
9
|
-
from simind_python_connector.utils.import_helpers import get_sirf_types
|
|
10
|
-
from simind_python_connector.utils.io_utils import temporary_directory
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
ImageData, _, SIRF_AVAILABLE = get_sirf_types()
|
|
9
|
+
from simind_python_connector.builders import _native
|
|
14
10
|
|
|
15
11
|
|
|
16
12
|
class STIRSPECTImageDataBuilder:
|
|
@@ -100,14 +96,11 @@ class STIRSPECTImageDataBuilder:
|
|
|
100
96
|
|
|
101
97
|
def build(self, output_path: Optional[str | Path] = None):
|
|
102
98
|
"""
|
|
103
|
-
Build and return the STIR
|
|
104
|
-
|
|
105
|
-
Returns:
|
|
106
|
-
ImageData: The constructed STIR ImageData object.
|
|
99
|
+
Build and return the image as a native SIRF or STIR object.
|
|
107
100
|
"""
|
|
108
101
|
data = self._resolve_data_array()
|
|
109
102
|
|
|
110
|
-
def _write(base_path: Path
|
|
103
|
+
def _write(base_path: Path):
|
|
111
104
|
header_path = base_path.with_suffix(".hv")
|
|
112
105
|
raw_path = base_path.with_suffix(".v")
|
|
113
106
|
self.header["!name of data file"] = raw_path.name
|
|
@@ -123,67 +116,13 @@ class STIRSPECTImageDataBuilder:
|
|
|
123
116
|
f.write(temp_str)
|
|
124
117
|
|
|
125
118
|
data.tofile(raw_path)
|
|
126
|
-
|
|
127
|
-
image_data = self._load_image(str(header_path))
|
|
128
|
-
|
|
129
|
-
if cleanup:
|
|
130
|
-
header_path.unlink(missing_ok=True)
|
|
131
|
-
raw_path.unlink(missing_ok=True)
|
|
132
|
-
return self._unwrap_native(image_data)
|
|
119
|
+
return _native.load_image(str(header_path), self.backend)
|
|
133
120
|
|
|
134
121
|
if output_path is None:
|
|
135
|
-
with
|
|
136
|
-
return _write(Path(tmp_dir) / "spect_image"
|
|
137
|
-
|
|
138
|
-
return _write(Path(output_path), cleanup=False)
|
|
139
|
-
|
|
140
|
-
def _load_image(self, header_path: str):
|
|
141
|
-
"""Load an image with optional explicit backend selection."""
|
|
142
|
-
if BACKEND_AVAILABLE and BACKENDS.factories.create_image_data is not None:
|
|
143
|
-
if (
|
|
144
|
-
self.backend is not None
|
|
145
|
-
and BACKENDS.detection.set_backend is not None
|
|
146
|
-
and BACKENDS.detection.get_backend is not None
|
|
147
|
-
):
|
|
148
|
-
previous_backend = None
|
|
149
|
-
try:
|
|
150
|
-
previous_backend = BACKENDS.detection.get_backend()
|
|
151
|
-
except Exception:
|
|
152
|
-
previous_backend = None
|
|
153
|
-
BACKENDS.detection.set_backend(self.backend)
|
|
154
|
-
try:
|
|
155
|
-
return BACKENDS.factories.create_image_data(header_path)
|
|
156
|
-
finally:
|
|
157
|
-
if (
|
|
158
|
-
previous_backend is not None
|
|
159
|
-
and previous_backend != self.backend
|
|
160
|
-
):
|
|
161
|
-
try:
|
|
162
|
-
BACKENDS.detection.set_backend(previous_backend)
|
|
163
|
-
except Exception:
|
|
164
|
-
pass
|
|
165
|
-
|
|
166
|
-
return BACKENDS.factories.create_image_data(header_path)
|
|
167
|
-
|
|
168
|
-
if self.backend == "stir":
|
|
169
|
-
raise ImportError(
|
|
170
|
-
"Requested STIR backend for image loading, "
|
|
171
|
-
"but backend wrappers are unavailable."
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
if SIRF_AVAILABLE:
|
|
175
|
-
return ImageData(header_path)
|
|
176
|
-
|
|
177
|
-
raise ImportError(
|
|
178
|
-
"Unable to load image data: neither SIRF nor STIR Python "
|
|
179
|
-
"backends are available."
|
|
180
|
-
)
|
|
122
|
+
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
123
|
+
return _write(Path(tmp_dir) / "spect_image")
|
|
181
124
|
|
|
182
|
-
|
|
183
|
-
def _unwrap_native(obj):
|
|
184
|
-
"""Return native backend object when a wrapper is provided."""
|
|
185
|
-
native = getattr(obj, "native_object", None)
|
|
186
|
-
return native if native is not None else obj
|
|
125
|
+
return _write(Path(output_path))
|
|
187
126
|
|
|
188
127
|
@staticmethod
|
|
189
128
|
def create_spect_uniform_image_from_sinogram(sinogram, origin=None):
|
|
@@ -202,10 +141,12 @@ class STIRSPECTImageDataBuilder:
|
|
|
202
141
|
ImageData: A uniform SPECT image initialized with the computed dimensions
|
|
203
142
|
and voxel sizes.
|
|
204
143
|
"""
|
|
205
|
-
|
|
144
|
+
try:
|
|
145
|
+
import sirf.STIR
|
|
146
|
+
except ImportError as exc:
|
|
206
147
|
raise ImportError(
|
|
207
148
|
"create_spect_uniform_image_from_sinogram requires the SIRF backend."
|
|
208
|
-
)
|
|
149
|
+
) from exc
|
|
209
150
|
|
|
210
151
|
# Create a uniform image from the sinogram and adjust z-voxel size.
|
|
211
152
|
image = sinogram.create_uniform_image(1)
|
|
@@ -224,6 +165,6 @@ class STIRSPECTImageDataBuilder:
|
|
|
224
165
|
origin = (0, 0, 0)
|
|
225
166
|
|
|
226
167
|
# Initialize a new image with computed dimensions, voxel sizes, and origin.
|
|
227
|
-
new_image = ImageData()
|
|
168
|
+
new_image = sirf.STIR.ImageData()
|
|
228
169
|
new_image.initialise(tuple(dims), tuple(voxel_size), tuple(origin))
|
|
229
170
|
return new_image
|
|
@@ -4,23 +4,29 @@ Packaged scanner presets (YAML or SMC).
|
|
|
4
4
|
Example
|
|
5
5
|
-------
|
|
6
6
|
>>> from simind_python_connector.configs import get
|
|
7
|
-
>>> cfg = get("AnyScan.yaml") #
|
|
7
|
+
>>> cfg = get("AnyScan.yaml") # Traversable
|
|
8
8
|
|
|
9
9
|
>>> from simind_python_connector.core import SimulationConfig
|
|
10
10
|
>>> sim_cfg = SimulationConfig(cfg) # load file
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
from importlib import resources as _res
|
|
14
|
-
from pathlib import Path
|
|
15
14
|
from typing import Union
|
|
16
15
|
|
|
17
16
|
|
|
17
|
+
try: # Python 3.11 moved Traversable into importlib.resources.abc
|
|
18
|
+
from importlib.resources.abc import Traversable
|
|
19
|
+
except ImportError: # pragma: no cover - Python 3.10
|
|
20
|
+
from importlib.abc import Traversable
|
|
21
|
+
|
|
22
|
+
|
|
18
23
|
__all__ = ["get", "list"]
|
|
19
24
|
|
|
20
25
|
|
|
21
|
-
def get(name: str) ->
|
|
26
|
+
def get(name: str) -> Traversable:
|
|
22
27
|
"""
|
|
23
|
-
Return
|
|
28
|
+
Return the bundled config file as an importlib.resources Traversable (a Path for
|
|
29
|
+
normal installs).
|
|
24
30
|
|
|
25
31
|
Parameters
|
|
26
32
|
----------
|
|
@@ -8,7 +8,6 @@ import importlib
|
|
|
8
8
|
|
|
9
9
|
from .base import BaseConnector
|
|
10
10
|
from .python_connector import (
|
|
11
|
-
NumpyConnector,
|
|
12
11
|
ProjectionResult,
|
|
13
12
|
RuntimeOperator,
|
|
14
13
|
SimindPythonConnector,
|
|
@@ -33,7 +32,6 @@ def __getattr__(name):
|
|
|
33
32
|
|
|
34
33
|
__all__ = [
|
|
35
34
|
"BaseConnector",
|
|
36
|
-
"NumpyConnector",
|
|
37
35
|
"PyTomographySimindAdaptor",
|
|
38
36
|
"ProjectionResult",
|
|
39
37
|
"RuntimeOperator",
|