niftimesh 0.1.0__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.
- niftimesh-0.1.0/LICENSE +21 -0
- niftimesh-0.1.0/MANIFEST.in +7 -0
- niftimesh-0.1.0/PKG-INFO +113 -0
- niftimesh-0.1.0/README.md +68 -0
- niftimesh-0.1.0/assets/closeup.png +0 -0
- niftimesh-0.1.0/assets/comparison.png +0 -0
- niftimesh-0.1.0/examples/README.md +14 -0
- niftimesh-0.1.0/examples/convert.py +37 -0
- niftimesh-0.1.0/examples/data/lung_lobe_seg.nii.gz +0 -0
- niftimesh-0.1.0/niftimesh/__init__.py +36 -0
- niftimesh-0.1.0/niftimesh/__main__.py +6 -0
- niftimesh-0.1.0/niftimesh/_version.py +1 -0
- niftimesh-0.1.0/niftimesh/builder.py +404 -0
- niftimesh-0.1.0/niftimesh/cli.py +80 -0
- niftimesh-0.1.0/niftimesh/convert.py +198 -0
- niftimesh-0.1.0/niftimesh/naive.py +70 -0
- niftimesh-0.1.0/niftimesh.egg-info/PKG-INFO +113 -0
- niftimesh-0.1.0/niftimesh.egg-info/SOURCES.txt +23 -0
- niftimesh-0.1.0/niftimesh.egg-info/dependency_links.txt +1 -0
- niftimesh-0.1.0/niftimesh.egg-info/entry_points.txt +2 -0
- niftimesh-0.1.0/niftimesh.egg-info/requires.txt +20 -0
- niftimesh-0.1.0/niftimesh.egg-info/top_level.txt +1 -0
- niftimesh-0.1.0/pyproject.toml +64 -0
- niftimesh-0.1.0/setup.cfg +4 -0
- niftimesh-0.1.0/tests/test_niftimesh.py +76 -0
niftimesh-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Justin
|
|
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.
|
niftimesh-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: niftimesh
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Watertight, smooth STL reconstruction from NIfTI segmentations (boolean-CSG peel or independent organs).
|
|
5
|
+
Author: Justin
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/77even/NiftiMesh
|
|
8
|
+
Project-URL: Repository, https://github.com/77even/NiftiMesh
|
|
9
|
+
Project-URL: Issues, https://github.com/77even/NiftiMesh/issues
|
|
10
|
+
Keywords: nifti,stl,segmentation,marching-cubes,mesh,medical-imaging,csg,vtk,meshlib,3d-reconstruction,surface
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Intended Audience :: Healthcare Industry
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
24
|
+
Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
|
|
25
|
+
Requires-Python: >=3.9
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: numpy>=1.21
|
|
29
|
+
Requires-Dist: scipy>=1.7
|
|
30
|
+
Requires-Dist: vtk>=9.1
|
|
31
|
+
Requires-Dist: nibabel>=3.2
|
|
32
|
+
Provides-Extra: csg
|
|
33
|
+
Requires-Dist: meshlib>=3.0; extra == "csg"
|
|
34
|
+
Provides-Extra: sitk
|
|
35
|
+
Requires-Dist: SimpleITK>=2.0; extra == "sitk"
|
|
36
|
+
Provides-Extra: all
|
|
37
|
+
Requires-Dist: meshlib>=3.0; extra == "all"
|
|
38
|
+
Requires-Dist: SimpleITK>=2.0; extra == "all"
|
|
39
|
+
Provides-Extra: dev
|
|
40
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
41
|
+
Requires-Dist: meshlib>=3.0; extra == "dev"
|
|
42
|
+
Requires-Dist: build; extra == "dev"
|
|
43
|
+
Requires-Dist: twine; extra == "dev"
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
|
|
46
|
+
<div align="center">
|
|
47
|
+
|
|
48
|
+
# NiftiMesh
|
|
49
|
+
|
|
50
|
+
**Watertight, smooth STL reconstruction from NIfTI segmentations.**
|
|
51
|
+
|
|
52
|
+
[](https://pypi.org/project/niftimesh/)
|
|
53
|
+
[](https://pypi.org/project/niftimesh/)
|
|
54
|
+
[](LICENSE)
|
|
55
|
+
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
Turn a multi-label `.nii.gz` segmentation into one clean, closed STL surface per
|
|
59
|
+
label — **solid, watertight, manifold, self-intersection-free**. In `csg` mode,
|
|
60
|
+
adjacent regions share their interface seam *bit-identically*, so the parts
|
|
61
|
+
assemble seamlessly in 3D Slicer / Mimics.
|
|
62
|
+
|
|
63
|
+
<img src="https://raw.githubusercontent.com/77even/NiftiMesh/main/assets/comparison.png" width="100%">
|
|
64
|
+
<img src="https://raw.githubusercontent.com/77even/NiftiMesh/main/assets/closeup.png" width="100%">
|
|
65
|
+
|
|
66
|
+
*Left → right: naive marching cubes (voxel staircase) · a typical 3D Slicer
|
|
67
|
+
default export · NiftiMesh (smooth, watertight, seamless).*
|
|
68
|
+
|
|
69
|
+
## What it's for
|
|
70
|
+
|
|
71
|
+
A multi-label segmentation volume → per-label STL meshes. Two modes:
|
|
72
|
+
|
|
73
|
+
- **`csg`** — for **one structure split by internal interfaces**: lung lobes /
|
|
74
|
+
segments, Couinaud liver segments. Neighbouring labels share their cut seam
|
|
75
|
+
exactly (no crack, no black line).
|
|
76
|
+
- **`independent`** — for **disjoint organs** (liver + spleen + kidneys, vessels):
|
|
77
|
+
each label becomes its own closed, smoothed surface.
|
|
78
|
+
|
|
79
|
+
You define the output names — nothing is hard-coded to any anatomy.
|
|
80
|
+
|
|
81
|
+
## Install
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pip install "niftimesh[csg]" # csg mode (needs meshlib)
|
|
85
|
+
pip install niftimesh # independent + naive modes only
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Python ≥ 3.9. NIfTI is read via `nibabel` (bundled) or `SimpleITK` if installed.
|
|
89
|
+
|
|
90
|
+
## Usage
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# names from a JSON file: {"1": "left_lower_lobe", "2": "left_upper_lobe", ...}
|
|
94
|
+
niftimesh seg.nii.gz out/ --mode csg --label-names names.json --suffix _3d
|
|
95
|
+
|
|
96
|
+
# omit --label-names to get label_1.stl, label_2.stl, ...
|
|
97
|
+
niftimesh organs.nii.gz out/ --mode independent
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from niftimesh import nifti_to_stl
|
|
102
|
+
|
|
103
|
+
nifti_to_stl("seg.nii.gz", "out/", mode="csg",
|
|
104
|
+
label_names={1: "left_lower_lobe", 2: "left_upper_lobe"})
|
|
105
|
+
|
|
106
|
+
# in-memory: numpy (z, y, x) label volume -> {label: vtkPolyData}
|
|
107
|
+
from niftimesh import reconstruct
|
|
108
|
+
meshes = reconstruct(seg, spacing=(0.84, 0.84, 1.0), mode="independent")
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
[MIT](LICENSE) © 2026 Justin
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# NiftiMesh
|
|
4
|
+
|
|
5
|
+
**Watertight, smooth STL reconstruction from NIfTI segmentations.**
|
|
6
|
+
|
|
7
|
+
[](https://pypi.org/project/niftimesh/)
|
|
8
|
+
[](https://pypi.org/project/niftimesh/)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
Turn a multi-label `.nii.gz` segmentation into one clean, closed STL surface per
|
|
14
|
+
label — **solid, watertight, manifold, self-intersection-free**. In `csg` mode,
|
|
15
|
+
adjacent regions share their interface seam *bit-identically*, so the parts
|
|
16
|
+
assemble seamlessly in 3D Slicer / Mimics.
|
|
17
|
+
|
|
18
|
+
<img src="https://raw.githubusercontent.com/77even/NiftiMesh/main/assets/comparison.png" width="100%">
|
|
19
|
+
<img src="https://raw.githubusercontent.com/77even/NiftiMesh/main/assets/closeup.png" width="100%">
|
|
20
|
+
|
|
21
|
+
*Left → right: naive marching cubes (voxel staircase) · a typical 3D Slicer
|
|
22
|
+
default export · NiftiMesh (smooth, watertight, seamless).*
|
|
23
|
+
|
|
24
|
+
## What it's for
|
|
25
|
+
|
|
26
|
+
A multi-label segmentation volume → per-label STL meshes. Two modes:
|
|
27
|
+
|
|
28
|
+
- **`csg`** — for **one structure split by internal interfaces**: lung lobes /
|
|
29
|
+
segments, Couinaud liver segments. Neighbouring labels share their cut seam
|
|
30
|
+
exactly (no crack, no black line).
|
|
31
|
+
- **`independent`** — for **disjoint organs** (liver + spleen + kidneys, vessels):
|
|
32
|
+
each label becomes its own closed, smoothed surface.
|
|
33
|
+
|
|
34
|
+
You define the output names — nothing is hard-coded to any anatomy.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install "niftimesh[csg]" # csg mode (needs meshlib)
|
|
40
|
+
pip install niftimesh # independent + naive modes only
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Python ≥ 3.9. NIfTI is read via `nibabel` (bundled) or `SimpleITK` if installed.
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# names from a JSON file: {"1": "left_lower_lobe", "2": "left_upper_lobe", ...}
|
|
49
|
+
niftimesh seg.nii.gz out/ --mode csg --label-names names.json --suffix _3d
|
|
50
|
+
|
|
51
|
+
# omit --label-names to get label_1.stl, label_2.stl, ...
|
|
52
|
+
niftimesh organs.nii.gz out/ --mode independent
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from niftimesh import nifti_to_stl
|
|
57
|
+
|
|
58
|
+
nifti_to_stl("seg.nii.gz", "out/", mode="csg",
|
|
59
|
+
label_names={1: "left_lower_lobe", 2: "left_upper_lobe"})
|
|
60
|
+
|
|
61
|
+
# in-memory: numpy (z, y, x) label volume -> {label: vtkPolyData}
|
|
62
|
+
from niftimesh import reconstruct
|
|
63
|
+
meshes = reconstruct(seg, spacing=(0.84, 0.84, 1.0), mode="independent")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
[MIT](LICENSE) © 2026 Justin
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
`data/lung_lobe_seg.nii.gz` is a 5-label pulmonary-lobe segmentation
|
|
4
|
+
(238×512×512, ~211 KB) used as a sample.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pip install "niftimesh[csg]"
|
|
8
|
+
|
|
9
|
+
# Python: you define the label names (see convert.py)
|
|
10
|
+
python examples/convert.py
|
|
11
|
+
|
|
12
|
+
# CLI: names from a JSON file ({"1": "left_lower_lobe", ...}), or omit for label_<n>
|
|
13
|
+
niftimesh data/lung_lobe_seg.nii.gz out/ --mode csg --label-names names.json --suffix _3d
|
|
14
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Minimal end-to-end example: a NIfTI segmentation -> per-label STL files.
|
|
3
|
+
|
|
4
|
+
python examples/convert.py # uses the bundled lung-lobe sample
|
|
5
|
+
python examples/convert.py my_seg.nii.gz out_dir csg
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from niftimesh import nifti_to_stl
|
|
12
|
+
|
|
13
|
+
HERE = Path(__file__).resolve().parent
|
|
14
|
+
|
|
15
|
+
# You define the names. Here: the bundled 5-label lung-lobe sample.
|
|
16
|
+
LABEL_NAMES = {
|
|
17
|
+
1: "left_lower_lobe",
|
|
18
|
+
2: "left_upper_lobe",
|
|
19
|
+
3: "right_lower_lobe",
|
|
20
|
+
4: "right_middle_lobe",
|
|
21
|
+
5: "right_upper_lobe",
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main():
|
|
26
|
+
inp = sys.argv[1] if len(sys.argv) > 1 else str(HERE / "data" / "lung_lobe_seg.nii.gz")
|
|
27
|
+
out = sys.argv[2] if len(sys.argv) > 2 else "out"
|
|
28
|
+
mode = sys.argv[3] if len(sys.argv) > 3 else "csg"
|
|
29
|
+
|
|
30
|
+
written = nifti_to_stl(inp, out, mode=mode, label_names=LABEL_NAMES, suffix="_3d")
|
|
31
|
+
print(f"Wrote {len(written)} STL file(s) to {out}/:")
|
|
32
|
+
for p in written:
|
|
33
|
+
print(" ", Path(p).name)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
if __name__ == "__main__":
|
|
37
|
+
main()
|
|
Binary file
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""NiftiMesh -- watertight, smooth STL reconstruction from NIfTI segmentations.
|
|
2
|
+
|
|
3
|
+
Two reconstruction modes:
|
|
4
|
+
|
|
5
|
+
* ``csg`` -- boolean-CSG peel. Splits ONE connected structure by its
|
|
6
|
+
internal interfaces into per-label solids that share each
|
|
7
|
+
fissure seam bit-identically (lung lobes / segments,
|
|
8
|
+
Couinaud liver segments). No cracks, no black seam lines.
|
|
9
|
+
* ``independent`` -- each label built as its own closed, smoothed, watertight
|
|
10
|
+
surface (disjoint multi-organ scenes).
|
|
11
|
+
|
|
12
|
+
Quick start::
|
|
13
|
+
|
|
14
|
+
from niftimesh import nifti_to_stl
|
|
15
|
+
|
|
16
|
+
# one structure split by internal interfaces (lobes, segments) -> csg
|
|
17
|
+
nifti_to_stl("lobe_seg.nii.gz", "out/", mode="csg",
|
|
18
|
+
label_names={1: "left_lower", 2: "left_upper"})
|
|
19
|
+
|
|
20
|
+
# disjoint organs -> independent
|
|
21
|
+
nifti_to_stl("organs.nii.gz", "out/", mode="independent")
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from ._version import __version__
|
|
25
|
+
from .builder import CSGMeshBuilder
|
|
26
|
+
from .convert import nifti_to_stl, reconstruct, save_meshes
|
|
27
|
+
from .naive import build_naive
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"__version__",
|
|
31
|
+
"CSGMeshBuilder",
|
|
32
|
+
"nifti_to_stl",
|
|
33
|
+
"reconstruct",
|
|
34
|
+
"save_meshes",
|
|
35
|
+
"build_naive",
|
|
36
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|