mlarray 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.
- mlarray-0.0.9/.github/workflows/workflow.yml +67 -0
- mlarray-0.0.9/.gitignore +40 -0
- mlarray-0.0.9/API.md +78 -0
- mlarray-0.0.9/LICENSE +21 -0
- mlarray-0.0.9/MANIFEST.in +1 -0
- mlarray-0.0.9/PKG-INFO +247 -0
- mlarray-0.0.9/README.md +218 -0
- mlarray-0.0.9/SCHEMA.md +82 -0
- mlarray-0.0.9/assets/banner.png +0 -0
- mlarray-0.0.9/examples/example_channel.py +34 -0
- mlarray-0.0.9/examples/example_metadata_only.py +31 -0
- mlarray-0.0.9/examples/example_open.py +37 -0
- mlarray-0.0.9/examples/example_save_load.py +33 -0
- mlarray-0.0.9/mlarray/__init__.py +54 -0
- mlarray-0.0.9/mlarray/cli.py +58 -0
- mlarray-0.0.9/mlarray/meta.py +578 -0
- mlarray-0.0.9/mlarray/mlarray.py +576 -0
- mlarray-0.0.9/mlarray/utils.py +17 -0
- mlarray-0.0.9/mlarray.egg-info/PKG-INFO +247 -0
- mlarray-0.0.9/mlarray.egg-info/SOURCES.txt +30 -0
- mlarray-0.0.9/mlarray.egg-info/dependency_links.txt +1 -0
- mlarray-0.0.9/mlarray.egg-info/entry_points.txt +3 -0
- mlarray-0.0.9/mlarray.egg-info/requires.txt +11 -0
- mlarray-0.0.9/mlarray.egg-info/top_level.txt +1 -0
- mlarray-0.0.9/pyproject.toml +59 -0
- mlarray-0.0.9/setup.cfg +4 -0
- mlarray-0.0.9/tests/test_usage.py +158 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
permissions:
|
|
4
|
+
contents: read
|
|
5
|
+
id-token: write
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
push:
|
|
9
|
+
branches: ["main"]
|
|
10
|
+
tags:
|
|
11
|
+
- "v*"
|
|
12
|
+
pull_request:
|
|
13
|
+
branches: ["main"]
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
tests:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
strategy:
|
|
19
|
+
fail-fast: false
|
|
20
|
+
matrix:
|
|
21
|
+
python-version: ["3.10"]
|
|
22
|
+
steps:
|
|
23
|
+
- name: Checkout
|
|
24
|
+
uses: actions/checkout@v4
|
|
25
|
+
|
|
26
|
+
- name: Setup Python
|
|
27
|
+
uses: actions/setup-python@v5
|
|
28
|
+
with:
|
|
29
|
+
python-version: ${{ matrix.python-version }}
|
|
30
|
+
|
|
31
|
+
- name: Install dependencies
|
|
32
|
+
run: |
|
|
33
|
+
python -m pip install --upgrade pip
|
|
34
|
+
pip install -e .[dev]
|
|
35
|
+
|
|
36
|
+
- name: Run tests
|
|
37
|
+
run: |
|
|
38
|
+
pytest || if [ $? -eq 5 ]; then echo "No tests collected; skipping."; exit 0; else exit $?; fi
|
|
39
|
+
|
|
40
|
+
publish:
|
|
41
|
+
needs: tests
|
|
42
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
- name: Checkout
|
|
46
|
+
uses: actions/checkout@v4
|
|
47
|
+
|
|
48
|
+
- name: Setup Python
|
|
49
|
+
uses: actions/setup-python@v5
|
|
50
|
+
with:
|
|
51
|
+
python-version: "3.10"
|
|
52
|
+
|
|
53
|
+
- name: Install build tooling
|
|
54
|
+
run: |
|
|
55
|
+
python -m pip install --upgrade pip
|
|
56
|
+
pip install build twine setuptools_scm
|
|
57
|
+
|
|
58
|
+
- name: Build package
|
|
59
|
+
run: python -m build
|
|
60
|
+
|
|
61
|
+
- name: Check metadata
|
|
62
|
+
run: python -m twine check dist/*
|
|
63
|
+
|
|
64
|
+
- name: Publish to PyPI
|
|
65
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
66
|
+
with:
|
|
67
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
mlarray-0.0.9/.gitignore
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Virtual environments
|
|
7
|
+
.venv/
|
|
8
|
+
env/
|
|
9
|
+
venv/
|
|
10
|
+
.env
|
|
11
|
+
.python-version
|
|
12
|
+
|
|
13
|
+
# Distribution / packaging
|
|
14
|
+
.Python
|
|
15
|
+
build/
|
|
16
|
+
dist/
|
|
17
|
+
*.egg-info/
|
|
18
|
+
.eggs/
|
|
19
|
+
wheelhouse/
|
|
20
|
+
|
|
21
|
+
# Installer logs
|
|
22
|
+
pip-log.txt
|
|
23
|
+
pip-delete-this-directory.txt
|
|
24
|
+
|
|
25
|
+
# Unit test / coverage reports
|
|
26
|
+
.pytest_cache/
|
|
27
|
+
.coverage*
|
|
28
|
+
coverage.xml
|
|
29
|
+
htmlcov/
|
|
30
|
+
|
|
31
|
+
# Editors
|
|
32
|
+
.DS_Store
|
|
33
|
+
.vscode/
|
|
34
|
+
.idea/
|
|
35
|
+
*.swp
|
|
36
|
+
*.swo
|
|
37
|
+
|
|
38
|
+
# Blosc2 files
|
|
39
|
+
*.b2nd
|
|
40
|
+
*.mla
|
mlarray-0.0.9/API.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# MLArray Public API
|
|
2
|
+
|
|
3
|
+
This document lists the public API surface of `MLArray`.
|
|
4
|
+
|
|
5
|
+
## Class: `MLArray`
|
|
6
|
+
|
|
7
|
+
### Constructor
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
MLArray(
|
|
11
|
+
array: Union[np.ndarray, str, Path],
|
|
12
|
+
spacing: Optional[Union[List, Tuple, np.ndarray]] = None,
|
|
13
|
+
origin: Optional[Union[List, Tuple, np.ndarray]] = None,
|
|
14
|
+
direction: Optional[Union[List, Tuple, np.ndarray]] = None,
|
|
15
|
+
meta: Optional[Union[Dict, Meta]] = None,
|
|
16
|
+
mmap: bool = False,
|
|
17
|
+
num_threads: int = 1,
|
|
18
|
+
mode: str = "r",
|
|
19
|
+
copy: Optional["MLArray"] = None,
|
|
20
|
+
)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
| argument | type | description |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| array | Union[np.ndarray, str, Path] | Input data or file path. Use a numpy ndarray for in-memory arrays. Use a string or Path to load a ".b2nd" or ".mla" file. |
|
|
26
|
+
| spacing | Optional[Union[List, Tuple, np.ndarray]] | Spacing per axis. Provide a list/tuple/ndarray with length equal to the number of dimensions (e.g., [sx, sy, sz]). |
|
|
27
|
+
| origin | Optional[Union[List, Tuple, np.ndarray]] | Origin per axis. Provide a list/tuple/ndarray with length equal to the number of dimensions. |
|
|
28
|
+
| direction | Optional[Union[List, Tuple, np.ndarray]] | Direction cosine matrix. Provide a 2D list/tuple/ndarray with shape (ndims, ndims). |
|
|
29
|
+
| meta | Optional[Union[Dict, Meta]] | Free-form metadata dictionary or Meta instance. Must be JSON-serializable when saving. If meta is passed as a Dict, it will internally be converted into a Meta object with the dict being interpreted as meta.image metadata. |
|
|
30
|
+
| mmap | bool | Whether to keep the loaded array memory-mapped when loading from disk. If true, MLArray.array will be an blosc2.ndarray.NDArray, else np.ndarray. |
|
|
31
|
+
| num_threads | int | Number of threads for Blosc2 operations. |
|
|
32
|
+
| mode | str | Blosc2 open mode: 'r' read-only (default), 'a' read/write create if doesn't exist (not supported), 'w' create overwrite if exists (not supported). |
|
|
33
|
+
| copy | Optional[MLArray] | Another MLArray instance to copy metadata fields from. |
|
|
34
|
+
|
|
35
|
+
### Properties
|
|
36
|
+
|
|
37
|
+
| name | type | description |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| spacing | Optional[List[float]] | Image spacing per axis. |
|
|
40
|
+
| origin | Optional[List[float]] | Image origin per axis. |
|
|
41
|
+
| direction | Optional[List[List[float]]] | Direction cosine matrix. |
|
|
42
|
+
| affine | List[List[float]] | Affine transform matrix. |
|
|
43
|
+
| translation | List[float] | Translation vector from the affine. |
|
|
44
|
+
| scale | List[float] | Scale factors from the affine. |
|
|
45
|
+
| rotation | List[List[float]] | Rotation matrix from the affine. |
|
|
46
|
+
| shear | List[List[float]] | Shear matrix from the affine. |
|
|
47
|
+
| shape | Tuple[int, ...] | Shape of the underlying array. |
|
|
48
|
+
| ndims | int | Number of array dimensions. |
|
|
49
|
+
|
|
50
|
+
### Methods
|
|
51
|
+
|
|
52
|
+
| name | signature | description |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| save | `save(filepath, patch_size="default", chunk_size=None, block_size=None, clevel=8, codec=blosc2.Codec.ZSTD, num_threads=1)` | Save to `.b2nd` or `.mla`. |
|
|
55
|
+
| comp_blosc2_params | `comp_blosc2_params(image_size, patch_size, bytes_per_pixel=4, l1_cache_size_per_core_in_bytes=32768, l3_cache_size_per_core_in_bytes=1441792, safety_factor=0.8)` | Compute recommended chunk/block sizes. |
|
|
56
|
+
|
|
57
|
+
#### save arguments
|
|
58
|
+
|
|
59
|
+
| argument | type | description |
|
|
60
|
+
| --- | --- | --- |
|
|
61
|
+
| filepath | Union[str, Path] | Path to save the file. Must end with ".b2nd" or ".mla". |
|
|
62
|
+
| patch_size | Optional[Union[int, List, Tuple]] | Patch size hint for chunk/block optimization. Provide an int for isotropic sizes or a list/tuple with length equal to the number of dimensions. Use "default" to use the default patch size of 192. |
|
|
63
|
+
| chunk_size | Optional[Union[int, List, Tuple]] | Explicit chunk size. Provide an int or a tuple/list with length equal to the number of dimensions, or None to let Blosc2 decide. Ignored when patch_size is not None. |
|
|
64
|
+
| block_size | Optional[Union[int, List, Tuple]] | Explicit block size. Provide an int or a tuple/list with length equal to the number of dimensions, or None to let Blosc2 decide. Ignored when patch_size is not None. |
|
|
65
|
+
| clevel | int | Compression level from 0 (no compression) to 9 (maximum compression). |
|
|
66
|
+
| codec | blosc2.Codec | Compression codec to use. |
|
|
67
|
+
| num_threads | int | Number of threads to use for saving the file. |
|
|
68
|
+
|
|
69
|
+
#### comp_blosc2_params arguments
|
|
70
|
+
|
|
71
|
+
| argument | type | description |
|
|
72
|
+
| --- | --- | --- |
|
|
73
|
+
| image_size | Tuple[int, int, int, int] | Image shape. Use a 2D, 3D, or 4D size; 2D/3D inputs are internally expanded. |
|
|
74
|
+
| patch_size | Union[Tuple[int, int], Tuple[int, int, int]] | Patch size for spatial dimensions. Use a 2-tuple (x, y) or 3-tuple (x, y, z). |
|
|
75
|
+
| bytes_per_pixel | int | Number of bytes per element. Defaults to 4 for float32. |
|
|
76
|
+
| l1_cache_size_per_core_in_bytes | int | L1 cache per core in bytes. |
|
|
77
|
+
| l3_cache_size_per_core_in_bytes | int | L3 cache per core in bytes. |
|
|
78
|
+
| safety_factor | float | Safety factor to avoid filling caches. |
|
mlarray-0.0.9/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Karol Gotkowski
|
|
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 @@
|
|
|
1
|
+
recursive-include assets *
|
mlarray-0.0.9/PKG-INFO
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mlarray
|
|
3
|
+
Version: 0.0.9
|
|
4
|
+
Summary: A standardized blosc2 image reader and writer for medical images.
|
|
5
|
+
Author-email: Karol Gotkowski <karol.gotkowski@dkfz.de>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Karol-G/mlarray
|
|
8
|
+
Project-URL: Source, https://github.com/Karol-G/mlarray
|
|
9
|
+
Project-URL: Issues, https://github.com/Karol-G/mlarray/issues
|
|
10
|
+
Keywords: copier,template,python
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: blosc2>=3
|
|
20
|
+
Requires-Dist: numpy>=2
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
24
|
+
Requires-Dist: twine>=4.0; extra == "dev"
|
|
25
|
+
Requires-Dist: setuptools_scm[toml]>=8.0; extra == "dev"
|
|
26
|
+
Provides-Extra: all
|
|
27
|
+
Requires-Dist: medvol; extra == "all"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
<p align="center">
|
|
31
|
+
<img src="https://raw.githubusercontent.com/Karol-G/mlarray/main/assets/banner.png" alt="{ML Array} banner" width="700" />
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
<p align="center">
|
|
35
|
+
<a href="https://pypi.org/project/mlarray/"><img src="https://img.shields.io/pypi/v/mlarray?logo=pypi&color=brightgreen&cacheSeconds=300&v=2026-01-22" alt="PyPI" align="middle" /></a>
|
|
36
|
+
<a href="https://pypi.org/project/mlarray/"><img src="https://img.shields.io/pypi/pyversions/mlarray?logo=python&cacheSeconds=300&v=2026-01-22" alt="Python Version" align="middle" /></a>
|
|
37
|
+
<a href="https://github.com/Karol-G/mlarray/actions"><img src="https://img.shields.io/github/actions/workflow/status/Karol-G/mlarray/workflow.yml?branch=main&logo=github" alt="Tests" align="middle" /></a>
|
|
38
|
+
<a href="https://github.com/copier-org/copier"><img src="https://img.shields.io/badge/template-copier-2ebd59?logo=jinja" alt="Copier Template" align="middle" /></a>
|
|
39
|
+
<a href="https://github.com/Karol-G/mlarray/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Karol-G/mlarray" alt="License" align="middle" /></a>
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
**tl;dr:** Using large, medical or scientific images for Machine Learning? => Use MLArray
|
|
43
|
+
|
|
44
|
+
A standardized Blosc2 image reader and writer for medical images. The MLArray
|
|
45
|
+
file format (".mla") is a Blosc2-compressed container with standardized
|
|
46
|
+
metadata support for N-dimensional medical images. Plain ".b2nd" files are also
|
|
47
|
+
supported, but they do not participate in the MLArray metadata standard.
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
You can install mlarray via [pip](https://pypi.org/project/mlarray/):
|
|
52
|
+
```bash
|
|
53
|
+
pip install mlarray
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
To enable the `mlarray_convert` CLI command, install MLArray with the necessary extra dependencies:
|
|
57
|
+
```bash
|
|
58
|
+
pip install mlarray[all]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## API
|
|
62
|
+
|
|
63
|
+
See [API.md](API.md) for the full MLArray api, including argument
|
|
64
|
+
descriptions and types.
|
|
65
|
+
|
|
66
|
+
## Metadata schema
|
|
67
|
+
|
|
68
|
+
See [SCHEMA.md](SCHEMA.md) for the full MLArray metadata schema, including field
|
|
69
|
+
descriptions and types.
|
|
70
|
+
|
|
71
|
+
## Usage
|
|
72
|
+
|
|
73
|
+
Below are common usage patterns for loading, saving, and working with metadata.
|
|
74
|
+
|
|
75
|
+
### Default usage
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
import numpy as np
|
|
79
|
+
from mlarray import MLArray
|
|
80
|
+
|
|
81
|
+
array = np.random.random((128, 256, 256))
|
|
82
|
+
image = MLArray(array) # Create MLArray image
|
|
83
|
+
image.save("sample.mla")
|
|
84
|
+
|
|
85
|
+
image = MLArray("sample.mla") # Loads image
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Memory-mapped usage
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from mlarray import MLArray
|
|
92
|
+
import numpy as np
|
|
93
|
+
|
|
94
|
+
# read-only, partial access (default)
|
|
95
|
+
image = MLArray().open("sample.mla", mmap='r')
|
|
96
|
+
crop = image[10:20, 50:60] # Read crop
|
|
97
|
+
|
|
98
|
+
# read/write, partial access
|
|
99
|
+
image = MLArray().open("sample.mla", mmap='r+')
|
|
100
|
+
image[10:20, 50:60] *= 5 # Modify crop in memory and disk
|
|
101
|
+
|
|
102
|
+
# read/write, partial access, create/overwrite
|
|
103
|
+
array = np.random.random((128, 256, 256))
|
|
104
|
+
image = MLArray().open("sample.mla", shape=array.shape, dtype=array.dtype, mmap='w+')
|
|
105
|
+
image[...] = array # Modify image in memory and disk
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Metadata inspection and manipulation
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
import numpy as np
|
|
112
|
+
from mlarray import MLArray
|
|
113
|
+
|
|
114
|
+
array = np.random.random((64, 128, 128))
|
|
115
|
+
image = MLArray(
|
|
116
|
+
array,
|
|
117
|
+
spacing=(1.0, 1.0, 1.5),
|
|
118
|
+
origin=(10.0, 10.0, 30.0),
|
|
119
|
+
direction=[[1, 0, 0], [0, 1, 0], [0, 0, 1]],
|
|
120
|
+
meta={"patient_id": "123", "modality": "CT"}, # Any image metadata (for example raw DICOM metadata)
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
print(image.spacing) # [1.0, 1.0, 1.5]
|
|
124
|
+
print(image.origin) # [10.0, 10.0, 30.0]
|
|
125
|
+
print(image.meta.image) # {"patient_id": "123", "modality": "CT"}
|
|
126
|
+
|
|
127
|
+
image.spacing[1] = 5.3
|
|
128
|
+
image.meta.image["study_id"] = "study-001"
|
|
129
|
+
image.save("with-metadata.mla")
|
|
130
|
+
|
|
131
|
+
# Open memory-mapped
|
|
132
|
+
image = MLArray().open("with-metadata.mla", mmap='r+')
|
|
133
|
+
image.meta.image["study_id"] = "new-study" # Modify metadata
|
|
134
|
+
image.close() # Close and save metadata, only necessary to save modified metadata
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Copy metadata with overrides
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
import numpy as np
|
|
141
|
+
from mlarray import MLArray
|
|
142
|
+
|
|
143
|
+
base = MLArray("sample.mla")
|
|
144
|
+
array = np.random.random(base.shape)
|
|
145
|
+
|
|
146
|
+
image = MLArray(
|
|
147
|
+
array,
|
|
148
|
+
spacing=(0.8, 0.8, 1.0),
|
|
149
|
+
copy=base, # Copies all non-explicitly set arguments from base
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
image.save("copied-metadata.mla")
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Standardized metadata usage
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
import numpy as np
|
|
159
|
+
from mlarray import MLArray, Meta
|
|
160
|
+
|
|
161
|
+
array = np.random.random((64, 128, 128))
|
|
162
|
+
image = MLArray(
|
|
163
|
+
array,
|
|
164
|
+
meta=Meta(image={"patient_id": "123", "modality": "CT"}, is_seg=True), # Add metadata in a pre-defined format
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
print(image.meta.image) # {"patient_id": "123", "modality": "CT"}
|
|
168
|
+
print(image.meta.is_seg) # True
|
|
169
|
+
|
|
170
|
+
image.meta.image["study_id"] = "study-001"
|
|
171
|
+
image.meta.is_seg = False
|
|
172
|
+
image.save("with-metadata.mla")
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Patch size variants
|
|
176
|
+
|
|
177
|
+
Default patch size (192):
|
|
178
|
+
```python
|
|
179
|
+
from mlarray import MLArray
|
|
180
|
+
|
|
181
|
+
image = MLArray("sample.mla")
|
|
182
|
+
image.save("default-patch.mla") # Default patch_size is 'default' -> Isotropic patch size of 192 pixels
|
|
183
|
+
image.save("default-patch.mla", patch_size='default')
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Custom isotropic patch size (512):
|
|
187
|
+
```python
|
|
188
|
+
from mlarray import MLArray
|
|
189
|
+
|
|
190
|
+
image = MLArray("sample.mla")
|
|
191
|
+
image.save("patch-512.mla", patch_size=512)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Custom non-isotropic patch size:
|
|
195
|
+
```python
|
|
196
|
+
from mlarray import MLArray
|
|
197
|
+
|
|
198
|
+
image = MLArray("sample.mla")
|
|
199
|
+
image.save("patch-non-iso.mla", patch_size=(128, 192, 256))
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Manual chunk/block size:
|
|
203
|
+
```python
|
|
204
|
+
from mlarray import MLArray
|
|
205
|
+
|
|
206
|
+
image = MLArray("sample.mla")
|
|
207
|
+
image.save("manual-chunk-block.mla", chunk_size=(1, 128, 128), block_size=(1, 32, 32))
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Let Blosc2 itself configure chunk/block size:
|
|
211
|
+
```python
|
|
212
|
+
from mlarray import MLArray
|
|
213
|
+
|
|
214
|
+
image = MLArray("sample.mla")
|
|
215
|
+
# If patch_size, chunk_size and block_size are all None, Blosc2 will auto-configure chunk and block size
|
|
216
|
+
image.save("manual-chunk-block.mla", patch_size=None)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## CLI
|
|
220
|
+
|
|
221
|
+
### mlarray_header
|
|
222
|
+
|
|
223
|
+
Print the metadata header from a `.mla` or `.b2nd` file.
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
mlarray_header sample.mla
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### mlarray_convert
|
|
230
|
+
|
|
231
|
+
Convert a NIfTI or NRRD file to MLArray and copy metadata.
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
mlarray_convert sample.nii.gz output.mla
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Contributing
|
|
238
|
+
|
|
239
|
+
Contributions are welcome! Please open a pull request with clear changes and add tests when appropriate.
|
|
240
|
+
|
|
241
|
+
## Issues
|
|
242
|
+
|
|
243
|
+
Found a bug or have a request? Open an issue at https://github.com/Karol-G/mlarray/issues.
|
|
244
|
+
|
|
245
|
+
## License
|
|
246
|
+
|
|
247
|
+
Distributed under the MIT license. See `LICENSE` for details.
|
mlarray-0.0.9/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/Karol-G/mlarray/main/assets/banner.png" alt="{ML Array} banner" width="700" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://pypi.org/project/mlarray/"><img src="https://img.shields.io/pypi/v/mlarray?logo=pypi&color=brightgreen&cacheSeconds=300&v=2026-01-22" alt="PyPI" align="middle" /></a>
|
|
7
|
+
<a href="https://pypi.org/project/mlarray/"><img src="https://img.shields.io/pypi/pyversions/mlarray?logo=python&cacheSeconds=300&v=2026-01-22" alt="Python Version" align="middle" /></a>
|
|
8
|
+
<a href="https://github.com/Karol-G/mlarray/actions"><img src="https://img.shields.io/github/actions/workflow/status/Karol-G/mlarray/workflow.yml?branch=main&logo=github" alt="Tests" align="middle" /></a>
|
|
9
|
+
<a href="https://github.com/copier-org/copier"><img src="https://img.shields.io/badge/template-copier-2ebd59?logo=jinja" alt="Copier Template" align="middle" /></a>
|
|
10
|
+
<a href="https://github.com/Karol-G/mlarray/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Karol-G/mlarray" alt="License" align="middle" /></a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
**tl;dr:** Using large, medical or scientific images for Machine Learning? => Use MLArray
|
|
14
|
+
|
|
15
|
+
A standardized Blosc2 image reader and writer for medical images. The MLArray
|
|
16
|
+
file format (".mla") is a Blosc2-compressed container with standardized
|
|
17
|
+
metadata support for N-dimensional medical images. Plain ".b2nd" files are also
|
|
18
|
+
supported, but they do not participate in the MLArray metadata standard.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
You can install mlarray via [pip](https://pypi.org/project/mlarray/):
|
|
23
|
+
```bash
|
|
24
|
+
pip install mlarray
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
To enable the `mlarray_convert` CLI command, install MLArray with the necessary extra dependencies:
|
|
28
|
+
```bash
|
|
29
|
+
pip install mlarray[all]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## API
|
|
33
|
+
|
|
34
|
+
See [API.md](API.md) for the full MLArray api, including argument
|
|
35
|
+
descriptions and types.
|
|
36
|
+
|
|
37
|
+
## Metadata schema
|
|
38
|
+
|
|
39
|
+
See [SCHEMA.md](SCHEMA.md) for the full MLArray metadata schema, including field
|
|
40
|
+
descriptions and types.
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
Below are common usage patterns for loading, saving, and working with metadata.
|
|
45
|
+
|
|
46
|
+
### Default usage
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
import numpy as np
|
|
50
|
+
from mlarray import MLArray
|
|
51
|
+
|
|
52
|
+
array = np.random.random((128, 256, 256))
|
|
53
|
+
image = MLArray(array) # Create MLArray image
|
|
54
|
+
image.save("sample.mla")
|
|
55
|
+
|
|
56
|
+
image = MLArray("sample.mla") # Loads image
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Memory-mapped usage
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from mlarray import MLArray
|
|
63
|
+
import numpy as np
|
|
64
|
+
|
|
65
|
+
# read-only, partial access (default)
|
|
66
|
+
image = MLArray().open("sample.mla", mmap='r')
|
|
67
|
+
crop = image[10:20, 50:60] # Read crop
|
|
68
|
+
|
|
69
|
+
# read/write, partial access
|
|
70
|
+
image = MLArray().open("sample.mla", mmap='r+')
|
|
71
|
+
image[10:20, 50:60] *= 5 # Modify crop in memory and disk
|
|
72
|
+
|
|
73
|
+
# read/write, partial access, create/overwrite
|
|
74
|
+
array = np.random.random((128, 256, 256))
|
|
75
|
+
image = MLArray().open("sample.mla", shape=array.shape, dtype=array.dtype, mmap='w+')
|
|
76
|
+
image[...] = array # Modify image in memory and disk
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Metadata inspection and manipulation
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
import numpy as np
|
|
83
|
+
from mlarray import MLArray
|
|
84
|
+
|
|
85
|
+
array = np.random.random((64, 128, 128))
|
|
86
|
+
image = MLArray(
|
|
87
|
+
array,
|
|
88
|
+
spacing=(1.0, 1.0, 1.5),
|
|
89
|
+
origin=(10.0, 10.0, 30.0),
|
|
90
|
+
direction=[[1, 0, 0], [0, 1, 0], [0, 0, 1]],
|
|
91
|
+
meta={"patient_id": "123", "modality": "CT"}, # Any image metadata (for example raw DICOM metadata)
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
print(image.spacing) # [1.0, 1.0, 1.5]
|
|
95
|
+
print(image.origin) # [10.0, 10.0, 30.0]
|
|
96
|
+
print(image.meta.image) # {"patient_id": "123", "modality": "CT"}
|
|
97
|
+
|
|
98
|
+
image.spacing[1] = 5.3
|
|
99
|
+
image.meta.image["study_id"] = "study-001"
|
|
100
|
+
image.save("with-metadata.mla")
|
|
101
|
+
|
|
102
|
+
# Open memory-mapped
|
|
103
|
+
image = MLArray().open("with-metadata.mla", mmap='r+')
|
|
104
|
+
image.meta.image["study_id"] = "new-study" # Modify metadata
|
|
105
|
+
image.close() # Close and save metadata, only necessary to save modified metadata
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Copy metadata with overrides
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
import numpy as np
|
|
112
|
+
from mlarray import MLArray
|
|
113
|
+
|
|
114
|
+
base = MLArray("sample.mla")
|
|
115
|
+
array = np.random.random(base.shape)
|
|
116
|
+
|
|
117
|
+
image = MLArray(
|
|
118
|
+
array,
|
|
119
|
+
spacing=(0.8, 0.8, 1.0),
|
|
120
|
+
copy=base, # Copies all non-explicitly set arguments from base
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
image.save("copied-metadata.mla")
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Standardized metadata usage
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
import numpy as np
|
|
130
|
+
from mlarray import MLArray, Meta
|
|
131
|
+
|
|
132
|
+
array = np.random.random((64, 128, 128))
|
|
133
|
+
image = MLArray(
|
|
134
|
+
array,
|
|
135
|
+
meta=Meta(image={"patient_id": "123", "modality": "CT"}, is_seg=True), # Add metadata in a pre-defined format
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
print(image.meta.image) # {"patient_id": "123", "modality": "CT"}
|
|
139
|
+
print(image.meta.is_seg) # True
|
|
140
|
+
|
|
141
|
+
image.meta.image["study_id"] = "study-001"
|
|
142
|
+
image.meta.is_seg = False
|
|
143
|
+
image.save("with-metadata.mla")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Patch size variants
|
|
147
|
+
|
|
148
|
+
Default patch size (192):
|
|
149
|
+
```python
|
|
150
|
+
from mlarray import MLArray
|
|
151
|
+
|
|
152
|
+
image = MLArray("sample.mla")
|
|
153
|
+
image.save("default-patch.mla") # Default patch_size is 'default' -> Isotropic patch size of 192 pixels
|
|
154
|
+
image.save("default-patch.mla", patch_size='default')
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Custom isotropic patch size (512):
|
|
158
|
+
```python
|
|
159
|
+
from mlarray import MLArray
|
|
160
|
+
|
|
161
|
+
image = MLArray("sample.mla")
|
|
162
|
+
image.save("patch-512.mla", patch_size=512)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Custom non-isotropic patch size:
|
|
166
|
+
```python
|
|
167
|
+
from mlarray import MLArray
|
|
168
|
+
|
|
169
|
+
image = MLArray("sample.mla")
|
|
170
|
+
image.save("patch-non-iso.mla", patch_size=(128, 192, 256))
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Manual chunk/block size:
|
|
174
|
+
```python
|
|
175
|
+
from mlarray import MLArray
|
|
176
|
+
|
|
177
|
+
image = MLArray("sample.mla")
|
|
178
|
+
image.save("manual-chunk-block.mla", chunk_size=(1, 128, 128), block_size=(1, 32, 32))
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Let Blosc2 itself configure chunk/block size:
|
|
182
|
+
```python
|
|
183
|
+
from mlarray import MLArray
|
|
184
|
+
|
|
185
|
+
image = MLArray("sample.mla")
|
|
186
|
+
# If patch_size, chunk_size and block_size are all None, Blosc2 will auto-configure chunk and block size
|
|
187
|
+
image.save("manual-chunk-block.mla", patch_size=None)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## CLI
|
|
191
|
+
|
|
192
|
+
### mlarray_header
|
|
193
|
+
|
|
194
|
+
Print the metadata header from a `.mla` or `.b2nd` file.
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
mlarray_header sample.mla
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### mlarray_convert
|
|
201
|
+
|
|
202
|
+
Convert a NIfTI or NRRD file to MLArray and copy metadata.
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
mlarray_convert sample.nii.gz output.mla
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Contributing
|
|
209
|
+
|
|
210
|
+
Contributions are welcome! Please open a pull request with clear changes and add tests when appropriate.
|
|
211
|
+
|
|
212
|
+
## Issues
|
|
213
|
+
|
|
214
|
+
Found a bug or have a request? Open an issue at https://github.com/Karol-G/mlarray/issues.
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
Distributed under the MIT license. See `LICENSE` for details.
|