nifti2bids 0.0.9__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.

Potentially problematic release.


This version of nifti2bids might be problematic. Click here for more details.

@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Donisha Smith
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.4
2
+ Name: nifti2bids
3
+ Version: 0.0.9
4
+ Summary: Post-hoc BIDS conversion toolkit for NIfTI datasets without original DICOMs.
5
+ Author-email: Donisha Smith <dsmit420@jhu.edu>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://nifti2bids.readthedocs.io
8
+ Project-URL: Github, https://github.com/donishadsmith/nifti2bids
9
+ Project-URL: Issues, https://github.com/donishadsmith/nifti2bids/issues
10
+ Project-URL: Changelog, https://nifti2bids.readthedocs.io/en/stable/changelog.html
11
+ Keywords: python,neuroimaging,fMRI,MRI,BIDS,NIfTI
12
+ Classifier: Intended Audience :: Education
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Topic :: Scientific/Engineering
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Operating System :: MacOS :: MacOS X
21
+ Classifier: Operating System :: POSIX :: Linux
22
+ Classifier: Operating System :: Microsoft :: Windows :: Windows 11
23
+ Classifier: Development Status :: 3 - Alpha
24
+ Requires-Python: >=3.10.0
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: numpy>=1.26.3
28
+ Requires-Dist: nibabel>=5.0.0
29
+ Requires-Dist: rich>=14.2.0
30
+ Requires-Dist: nilearn>=0.10.4
31
+ Requires-Dist: pandas>=2.1.0
32
+ Provides-Extra: all
33
+ Requires-Dist: nifti2bids[test]; extra == "all"
34
+ Provides-Extra: test
35
+ Requires-Dist: pytest; extra == "test"
36
+ Requires-Dist: pytest-cov; extra == "test"
37
+ Dynamic: license-file
38
+
39
+ # Nifti2Bids
40
+
41
+ [![Latest Version](https://img.shields.io/pypi/v/nifti2bids.svg)](https://pypi.python.org/pypi/nifti2bids/)
42
+ [![Python Versions](https://img.shields.io/pypi/pyversions/nifti2bids.svg)](https://pypi.python.org/pypi/nifti2bids/)
43
+ [![Source Code](https://img.shields.io/badge/Source%20Code-nifti2bids-purple)](https://github.com/donishadsmith/nifti2bids)
44
+ [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
45
+ [![Test Status](https://github.com/donishadsmith/nifti2bids/actions/workflows/testing.yaml/badge.svg)](https://github.com/donishadsmith/nifti2bids/actions/workflows/testing.yaml)
46
+ [![codecov](https://codecov.io/gh/donishadsmith/nifti2bids/graph/badge.svg?token=PCJ17NA627)](https://codecov.io/gh/donishadsmith/nifti2bids)
47
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
48
+ [![Documentation Status](https://readthedocs.org/projects/nifti2bids-py/badge/?version=latest)](http://nifti2bids.readthedocs.io/en/latest/?badge=latest)
49
+
50
+
51
+ A toolkit for post hoc BIDS-ification NIfTI datasets. Includes utilities for metadata extraction, file renaming, and JSON sidecar generation, designed primarily for datasets where the original DICOMs are unavailable.
52
+
53
+ ## Installation
54
+ To install ``nifti2bids`` use one of the following methods:
55
+
56
+ ### Standard Installation
57
+ ```bash
58
+ pip install nifti2bids
59
+ ```
60
+
61
+ ### Development Version
62
+
63
+ ```bash
64
+ git clone --depth 1 https://github.com/donishadsmith/nifti2bids/
65
+ cd nifti2bids
66
+ pip install -e .
67
+ ```
@@ -0,0 +1,29 @@
1
+ # Nifti2Bids
2
+
3
+ [![Latest Version](https://img.shields.io/pypi/v/nifti2bids.svg)](https://pypi.python.org/pypi/nifti2bids/)
4
+ [![Python Versions](https://img.shields.io/pypi/pyversions/nifti2bids.svg)](https://pypi.python.org/pypi/nifti2bids/)
5
+ [![Source Code](https://img.shields.io/badge/Source%20Code-nifti2bids-purple)](https://github.com/donishadsmith/nifti2bids)
6
+ [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+ [![Test Status](https://github.com/donishadsmith/nifti2bids/actions/workflows/testing.yaml/badge.svg)](https://github.com/donishadsmith/nifti2bids/actions/workflows/testing.yaml)
8
+ [![codecov](https://codecov.io/gh/donishadsmith/nifti2bids/graph/badge.svg?token=PCJ17NA627)](https://codecov.io/gh/donishadsmith/nifti2bids)
9
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
10
+ [![Documentation Status](https://readthedocs.org/projects/nifti2bids-py/badge/?version=latest)](http://nifti2bids.readthedocs.io/en/latest/?badge=latest)
11
+
12
+
13
+ A toolkit for post hoc BIDS-ification NIfTI datasets. Includes utilities for metadata extraction, file renaming, and JSON sidecar generation, designed primarily for datasets where the original DICOMs are unavailable.
14
+
15
+ ## Installation
16
+ To install ``nifti2bids`` use one of the following methods:
17
+
18
+ ### Standard Installation
19
+ ```bash
20
+ pip install nifti2bids
21
+ ```
22
+
23
+ ### Development Version
24
+
25
+ ```bash
26
+ git clone --depth 1 https://github.com/donishadsmith/nifti2bids/
27
+ cd nifti2bids
28
+ pip install -e .
29
+ ```
@@ -0,0 +1 @@
1
+ __version__ = "0.0.9"
@@ -0,0 +1,53 @@
1
+ """Decorator functions."""
2
+
3
+ import functools, inspect
4
+
5
+ from typing import Any, Callable
6
+
7
+ from ._helpers import list_to_str
8
+
9
+
10
+ def check_all_none(parameter_names: list[str]) -> Callable:
11
+ """
12
+ Checks if specific parameters are assigned ``None``.
13
+
14
+ Parameters
15
+ ----------
16
+ parameter_names: :obj:`list[str]`
17
+ List of parameter names to check.
18
+
19
+ Returns
20
+ -------
21
+ Callable
22
+ Decorator function wrapping target function.
23
+ """
24
+
25
+ def decorator(func: Callable) -> Callable:
26
+ signature = inspect.signature(func)
27
+ if invalid_params := [
28
+ param
29
+ for param in parameter_names
30
+ if param not in signature.parameters.keys()
31
+ ]:
32
+ raise NameError(
33
+ "Error in ``parameter_names`` of decorator. The following "
34
+ f"parameters are not in the signature of '{func.__name__}': "
35
+ f"{list_to_str(invalid_params)}."
36
+ )
37
+
38
+ @functools.wraps(func)
39
+ def wrapper(*args: Any, **kwargs: Any) -> Callable:
40
+ bound_args = signature.bind(*args, **kwargs)
41
+ bound_args.apply_defaults()
42
+ all_param_values = [bound_args.arguments[name] for name in parameter_names]
43
+ if all(value is None for value in all_param_values):
44
+ raise ValueError(
45
+ "All of the following arguments cannot be None, "
46
+ f"one must be specified: {list_to_str(parameter_names)}."
47
+ )
48
+
49
+ return func(*args, **kwargs)
50
+
51
+ return wrapper
52
+
53
+ return decorator
@@ -0,0 +1,51 @@
1
+ """Custom exceptions."""
2
+
3
+ from typing import Literal, Optional
4
+
5
+
6
+ class SliceAxisError(Exception):
7
+ """
8
+ Incorrect slice axis.
9
+
10
+ Raised when the number of slices does not match "slice_end" plus one.
11
+
12
+ Parameters
13
+ ----------
14
+ slice_axis: :obj:`Literal["x", "y", "z"]`
15
+ The specified slice dimension.
16
+
17
+ n_slices: :obj:`int`
18
+ The number of slices from the specified ``slice_axis``.
19
+
20
+ slice_end: :obj:`int`
21
+ The number of slices specified by "slice_end" in the NIfTI header.
22
+
23
+ message: :obj:`str` or :obj:`None`:
24
+ The error message. If None, a default error message is used.
25
+ """
26
+
27
+ def __init__(
28
+ self,
29
+ slice_axis: Literal["x", "y", "z"],
30
+ n_slices: int,
31
+ slice_end: int,
32
+ message: Optional[str] = None,
33
+ ):
34
+ if not message:
35
+ self.message = (
36
+ "Incorrect slice axis. Number of slices for "
37
+ f"{slice_axis} dimension is {n_slices} but "
38
+ f"'slice_end' in NIfTI header is {slice_end}."
39
+ )
40
+ else:
41
+ self.message = message
42
+
43
+ super().__init__(self.message)
44
+
45
+
46
+ class DataDimensionError(Exception):
47
+ """
48
+ Incorrect data dimensionality.
49
+ """
50
+
51
+ pass
@@ -0,0 +1,6 @@
1
+ """Helper functions."""
2
+
3
+
4
+ def list_to_str(str_list: list[str]) -> None:
5
+ """Converts a list containing strings to a string."""
6
+ return ", ".join(["'{a}'".format(a=x) for x in str_list])
@@ -0,0 +1,287 @@
1
+ """Module for input/output operations."""
2
+
3
+ import glob, json, os, shutil
4
+ from typing import Optional
5
+
6
+ import nibabel as nib
7
+
8
+
9
+ def load_nifti(
10
+ nifti_file_or_img: str | nib.nifti1.Nifti1Image,
11
+ ) -> nib.nifti1.Nifti1Image:
12
+ """
13
+ Loads a NIfTI image.
14
+
15
+ Loads NIfTI image when not a ``Nifti1Image`` object or
16
+ returns the image if already loaded in.
17
+
18
+ Parameters
19
+ ----------
20
+ nifti_file_or_img: :obj:`str` or :obj:`Nifti1Image`
21
+ Path to the NIfTI file or a NIfTI image.
22
+
23
+ Returns
24
+ -------
25
+ nib.nifti1.Nifti1Image
26
+ The loaded in NIfTI image.
27
+ """
28
+ nifti_img = (
29
+ nifti_file_or_img
30
+ if isinstance(nifti_file_or_img, nib.nifti1.Nifti1Image)
31
+ else nib.load(nifti_file_or_img)
32
+ )
33
+
34
+ return nifti_img
35
+
36
+
37
+ def compress_image(nifti_file: str, remove_src_file: bool = False) -> None:
38
+ """
39
+ Compresses a ".nii" image to a ".nii.gz" image.
40
+
41
+ Parameters
42
+ ----------
43
+ nifti_file: :obj:`str`
44
+ Path to the NIfTI image.
45
+
46
+ remove_src_file: :obj:`bool`
47
+ Deletes the original source image file.
48
+
49
+ Returns
50
+ -------
51
+ None
52
+ """
53
+ img = nib.load(nifti_file)
54
+ nib.save(img, nifti_file.replace(".nii", ".nii.gz"))
55
+
56
+ if remove_src_file:
57
+ os.remove(nifti_file)
58
+
59
+
60
+ def glob_contents(src_dir: str, pattern: str) -> list[str]:
61
+ """
62
+ Use glob to get contents with specific patterns.
63
+
64
+ Parameters
65
+ ----------
66
+ src_dir: :obj:`str`
67
+ The source directory.
68
+
69
+ ext: :obj:`str`
70
+ The extension.
71
+
72
+ Returns
73
+ -------
74
+ list[str]
75
+ List of contents with the pattern specified by ``pattern``.
76
+ """
77
+ return glob.glob(os.path.join(src_dir, f"*{pattern}"))
78
+
79
+
80
+ def get_nifti_header(nifti_file_or_img):
81
+ """
82
+ Get header from a NIfTI image.
83
+
84
+ Parameters
85
+ ----------
86
+ nifti_file_or_img: :obj:`str` or :obj:`Nifti1Image`
87
+ Path to the NIfTI file or a NIfTI image.
88
+
89
+ Returns
90
+ -------
91
+ nib.nifti1.Nifti1Image
92
+ The header from a NIfTI image.
93
+ """
94
+ return load_nifti(nifti_file_or_img).header
95
+
96
+
97
+ def get_nifti_affine(nifti_file_or_img):
98
+ """
99
+ Get the affine matrix from a NIfTI image.
100
+
101
+ Parameters
102
+ ----------
103
+ nifti_file_or_img: :obj:`str` or :obj:`Nifti1Image`
104
+ Path to the NIfTI file or a NIfTI image.
105
+
106
+ Returns
107
+ -------
108
+ nib.nifti1.Nifti1Image
109
+ The header from a NIfTI image.
110
+ """
111
+ return load_nifti(nifti_file_or_img).affine
112
+
113
+
114
+ def _copy_file(src_file: str, dst_file: str, remove_src_file: bool) -> None:
115
+ """
116
+ Copy a file and optionally remove the source file.
117
+
118
+ Parameters
119
+ ----------
120
+ src_file: :obj:`str`
121
+ The source file to be copied
122
+
123
+ dst_file: :obj:`str`
124
+ The new destination file.
125
+
126
+ remove_src_file: :obj:`bool`
127
+ Delete the source file if True.
128
+
129
+ Returns
130
+ -------
131
+ None
132
+ """
133
+ shutil.copy(src_file, dst_file)
134
+
135
+ if remove_src_file:
136
+ os.remove(src_file)
137
+
138
+
139
+ def create_bids_file(
140
+ nifti_file: str,
141
+ subj_id: str | int,
142
+ desc: str,
143
+ ses_id: Optional[str | int] = None,
144
+ task_id: Optional[str] = None,
145
+ run_id: Optional[str | int] = None,
146
+ dst_dir: str = None,
147
+ remove_src_file: bool = False,
148
+ return_bids_filename: bool = False,
149
+ ) -> str | None:
150
+ """
151
+ Create a BIDS compliant filename with required and optional entities.
152
+
153
+ Parameters
154
+ ----------
155
+ nifti_file: :obj:`str`
156
+ Path to NIfTI image.
157
+
158
+ sub_id: :obj:`str` or :obj:`int`
159
+ Subject ID (i.e. 01, 101, etc).
160
+
161
+ desc: :obj:`str`
162
+ Description of the file (i.e., T1w, bold, etc).
163
+
164
+ ses_id: :obj:`str` or :obj:`int` or :obj:`None`, default=None
165
+ Session ID (i.e. 001, 1, etc). Optional entity.
166
+
167
+ ses_id: :obj:`str` or :obj:`int` or :obj:`None`, default=None
168
+ Session ID (i.e. 001, 1, etc). Optional entity.
169
+
170
+ task_id: :obj:`str` or :obj:`None`, default=None
171
+ Task ID (i.e. flanker, n_back, etc). Optional entity.
172
+
173
+ run_id: :obj:`str` or :obj:`int` or :obj:`None`, default=None
174
+ Run ID (i.e. 001, 1, etc). Optional entity.
175
+
176
+ dst_dir: :obj:`str`, default=None
177
+ Directory name to copy the BIDS file to. If None, then the
178
+ BIDS file is copied to the same directory as
179
+
180
+ remove_src_file: :obj:`str`, default=False
181
+ Delete the source file if True.
182
+
183
+ return_bids_filename: :obj:`str`, default=False
184
+ Returns the full BIDS filename if True.
185
+
186
+ Returns
187
+ -------
188
+ None or str
189
+ If ``return_bids_filename`` is True, then the BIDS filename is
190
+ returned.
191
+
192
+ Note
193
+ ----
194
+ There are additional entities that can be used that are
195
+ not included in this function.
196
+ """
197
+ bids_filename = f"sub-{subj_id}_ses-{ses_id}_task-{task_id}_" f"run-{run_id}_{desc}"
198
+ bids_filename = _strip_none_entities(bids_filename)
199
+
200
+ ext = f"{nifti_file.partition('.')[-1]}"
201
+ bids_filename += f"{ext}"
202
+ bids_filename = (
203
+ os.path.join(os.path.dirname(nifti_file), bids_filename)
204
+ if dst_dir is None
205
+ else os.path.join(dst_dir, bids_filename)
206
+ )
207
+
208
+ _copy_file(nifti_file, bids_filename, remove_src_file)
209
+
210
+ return bids_filename if return_bids_filename else None
211
+
212
+
213
+ def _strip_none_entities(bids_filename: str) -> str:
214
+ """
215
+ Removes entities with None in a BIDS compliant filename.
216
+
217
+ Parameters
218
+ ----------
219
+ bids_filename: :obj:`str`
220
+ The BIDS filename.
221
+
222
+ Returns
223
+ -------
224
+ str
225
+ BIDS filename with entities ending in None removed.
226
+
227
+ Example
228
+ -------
229
+ >>> from bidsrep.io import _strip_none_entities
230
+ >>> bids_filename = "sub-101_ses-None_task-flanker_bold.nii.gz"
231
+ >>> _strip_none_entities(bids_filename)
232
+ "sub-101_task-flanker_bold.nii.gz"
233
+ """
234
+ basename, _, ext = bids_filename.partition(".")
235
+ retained_entities = [
236
+ entity for entity in basename.split("_") if not entity.endswith("-None")
237
+ ]
238
+
239
+ return f"{'_'.join(retained_entities)}.{ext}"
240
+
241
+
242
+ def create_dataset_description(dataset_name: str, bids_version: str = "1.0.0") -> dict:
243
+ """
244
+ Generate a dataset description dictionary.
245
+
246
+ Creates a dictionary containing the name and BIDs version of a dataset.
247
+
248
+ .. versionadded:: 0.34.1
249
+
250
+ Parameters
251
+ ----------
252
+ dataset_name: :obj:`str`
253
+ Name of the dataset.
254
+
255
+ bids_version: :obj:`str`,
256
+ Version of the BIDS dataset.
257
+
258
+ derivative: :obj:`bool`, default=False
259
+ Determines if "GeneratedBy" key is added to dictionary.
260
+
261
+ Returns
262
+ -------
263
+ dict
264
+ The dataset description dictionary
265
+ """
266
+ return {"Name": dataset_name, "BIDSVersion": bids_version}
267
+
268
+
269
+ def save_dataset_description(dataset_description: dict[str, str], dst_dir: str) -> None:
270
+ """
271
+ Save a dataset description dictionary.
272
+
273
+ Saves the dataset description dictionary as a file named "dataset_description.json" to the
274
+ directory specified by ``output_dir``.
275
+
276
+ Parameters
277
+ ----------
278
+ dataset_description: :obj:`dict`
279
+ The dataset description dictionary.
280
+
281
+ dst_dir: :obj:`str`
282
+ Path to save the JSON file to.
283
+ """
284
+ with open(
285
+ os.path.join(dst_dir, "dataset_description.json"), "w", encoding="utf-8"
286
+ ) as f:
287
+ json.dump(dataset_description, f)
@@ -0,0 +1,86 @@
1
+ """Module for logging."""
2
+
3
+ import logging
4
+ from typing import Optional
5
+
6
+ from rich.logging import RichHandler
7
+
8
+
9
+ def setup_logger(
10
+ logger_name: str = None, level: Optional[int] = None
11
+ ) -> logging.Logger:
12
+ """
13
+ Sets up the logger.
14
+
15
+ .. note::
16
+ Defaults to ``RichHandler`` if a module or root handler is
17
+ not detected.
18
+
19
+ Parameters
20
+ ----------
21
+ logger_name: :obj:`str`
22
+ Name of the logger to return, if None, the root logger is returned.
23
+
24
+ level: :obj:`int` or :obj:`None`
25
+ The logging level. If None, the logging level is not set
26
+
27
+ Returns
28
+ -------
29
+ Logger
30
+ A ``Logger`` object.
31
+ """
32
+ logger = logging.getLogger(logger_name)
33
+ if not _has_handler(logger):
34
+ logger = _add_default_handler(logger)
35
+
36
+ if level:
37
+ logger.setLevel(level)
38
+
39
+ return logger
40
+
41
+
42
+ def _has_handler(logger):
43
+ """
44
+ Check if a handler is present.
45
+
46
+ Checks the root logger and module logger.
47
+
48
+ logger: :obj:`Logger`
49
+ A logging object.
50
+
51
+ Returns
52
+ -------
53
+ bool
54
+ True if a handler is present and False if no handler is present
55
+ """
56
+ has_root_handler = logging.getLogger().hasHandlers()
57
+ has_module_handler = bool(logger.handlers)
58
+
59
+ return True if (has_root_handler or has_module_handler) else False
60
+
61
+
62
+ def _add_default_handler(logger: logging.Logger, format: str | None = None):
63
+ """
64
+ Add a default and format handler. Uses ``RichHandler`` as the default logger.
65
+
66
+ Parameters
67
+ ----------
68
+ logger: :obj:`Logger`
69
+ A logging object.
70
+
71
+ format: :obj:`str`
72
+ String specifying the format of the logged message.
73
+
74
+ Returns
75
+ -------
76
+ Logger
77
+ A logger object.
78
+ """
79
+
80
+ format = format if format else "%(asctime)s %(name)s [%(levelname)s] %(message)s"
81
+
82
+ handler = RichHandler()
83
+ handler.setFormatter(logging.Formatter(format))
84
+ logger.addHandler(handler)
85
+
86
+ return logger
@@ -0,0 +1,59 @@
1
+ """Module for creating simulated data."""
2
+
3
+ import nibabel as nib, numpy as np
4
+
5
+ from numpy.typing import NDArray
6
+
7
+
8
+ def simulate_nifti_image(
9
+ img_shape: tuple[int, int, int] | tuple[int, int, int, int], affine: NDArray = None
10
+ ) -> nib.Nifti1Image:
11
+ """
12
+ Simulates a NIfTI image.
13
+
14
+ Parameters
15
+ ----------
16
+ img_shape: :obj:`tuple[int, int, int]` or :obj:`tuple[int, int, int, int]`
17
+ Shape of the NIfTI image.
18
+
19
+ affine: :obj:`NDArray`, default=None
20
+ The affine matrix.
21
+
22
+ .. important::
23
+ If None, creates an identity matrix.
24
+
25
+ Returns
26
+ -------
27
+ Nifti1Image
28
+ The NIfTI image with no header.
29
+ """
30
+ if affine is None:
31
+ affine = create_affine(
32
+ xyz_diagonal_value=1, translation_vector=np.array([0, 0, 0, 1])
33
+ )
34
+
35
+ return nib.Nifti1Image(np.random.rand(*img_shape), affine)
36
+
37
+
38
+ def create_affine(xyz_diagonal_value: int, translation_vector: NDArray) -> NDArray:
39
+ """
40
+ Generate an 4x4 affine matrix.
41
+
42
+ Parameters
43
+ ----------
44
+ xyz_diagonal_value: :obj:`int`
45
+ The value assigned to the diagonal of the affine for x, y, and z.
46
+
47
+ translation_vector: :obj:`NDArray`
48
+ The translation vector/shift from the origin.
49
+
50
+ Returns
51
+ -------
52
+ NDArray
53
+ The affine matrix.
54
+ """
55
+ affine = np.zeros((4, 4))
56
+ np.fill_diagonal(affine[:3, :3], xyz_diagonal_value)
57
+ affine[:, 3:] = translation_vector[:, np.newaxis]
58
+
59
+ return affine