brain-stl 0.0.1__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Lukas Fisch
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,95 @@
1
+ Metadata-Version: 2.3
2
+ Name: brain-stl
3
+ Version: 0.0.1
4
+ Summary: Turn your brain MRI into a printable 3D model in seconds 🧠➡️🖨️
5
+ Home-page: https://github.com/codingfisch/brain_stl
6
+ License: MIT
7
+ Author: codingfisch
8
+ Author-email: l_fisc17@wwu.de
9
+ Requires-Python: >=3.9,<4.0
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
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
+ Requires-Dist: PyMCubes
20
+ Requires-Dist: dcm2niix
21
+ Requires-Dist: deepmriprep
22
+ Requires-Dist: fast_simplification (==0.1.7)
23
+ Requires-Dist: niftiview
24
+ Requires-Dist: trimesh
25
+ Project-URL: Repository, https://github.com/codingfisch/brain_stl
26
+ Description-Content-Type: text/markdown
27
+
28
+ # brain-stl 🧠
29
+ The **easiest** and **fastest** way to turn brain MRI scans into **3D printable models** 🖨️ powered by [`deepmriprep`](https://github.com/wwu-mmll/deepmriprep) ✨
30
+
31
+ [Use the Colab demo](https://colab.research.google.com/drive/10WSG_qmKnbYrFTwZOlXsIgbda8iz2duQ?usp=sharing) or **install** it locally via `pip install brain_stl` 💨
32
+
33
+ By default, the model is saved as `brain.stl`, but you can customize the filename along with other options like
34
+ - **Threshold**: Pick a value between 0 and 3 for different tissue types (see GIF left, `2.5`: white matter only) 🧠
35
+ - **Hollowness**: Adjust how hollow the brain is (enables faster printing) 💨
36
+ - **Text**: Add personalized text that works as a support structure 🔤
37
+ - **Smoothing**: Achieve a polished surface via iterative Laplacian smoothing ✨
38
+ - **Mesh Reduction**: Simplify the mesh to reduce the size of `brain.stl` ✂️
39
+
40
+ ![gif](https://github.com/user-attachments/assets/64f10b4f-b136-4e86-8ef4-37f9fe0d8fa7)
41
+
42
+ ## Usage 💻
43
+ To get your first `brain.stl` just run
44
+ ```python
45
+ from brain_stl import run_brain_stl
46
+
47
+ run_brain_stl() # per default output_folder='.' (current folder)
48
+ ```
49
+ and a publicly available brain MRI scan (from [OpenNeuro](https://openneuro.org/)) will be used 🌐
50
+
51
+ Scan files can be inputted in NifTi (`.nii` or `.nii.gz`) or DICOM (`.dcm` or [folder](https://pydicom.github.io/pydicom/stable/tutorials/filesets.html)) format
52
+ ```python
53
+ from brain_stl import run_brain_stl
54
+
55
+ run_brain_stl('/path/to/scan.nii.gz') # or '/path/to/dicom_folder'
56
+ ```
57
+ The main arguments of `run_brain_stl` are
58
+ - **`scan_filepath`**: Path to the input scan (if `None`, use scan from `url`). Default: `None`
59
+ - **`output_folder`**: Folder to save the `.stl` file and other outputs. Default: `'.'`
60
+ - **`stl_name`**: Name of the example `.stl` file (without extension). Default: `'brain'`
61
+
62
+ <details>
63
+ <summary><b>Click here</b>, to see <b>all</b> remaining <b>arguments</b> 📑</summary>
64
+
65
+ - **`nifti_name`**: If DICOM produces multiple NifTis, this NifTi filename is used to proceed. Default: `None`
66
+ - **`url`**: URL to download a brain scan if no `scan_filepath` is provided. Default: `OPENNEURO_URL`
67
+ - **`use_cache`**: If `True`, reuses intermediate outputs (e.g., tissue data). Default: `False`
68
+ - **`threshold`**: Threshold tissue value (`0.5`: fluid, `1.5`: gray matter, `2.5`: white matter). Default: `1.5`
69
+ - **`hollow`**: How hollow the brain is (0 to 1). Default: `0`
70
+ - **`in_template_space`**: If `True`, the 3D model is in standardized (template) orientation. Default: `False`
71
+ - **`mesh_reduction`**: Fraction of mesh reduction (0 to 1) for smaller `.stl` file size. Default: `0` (no reduction)
72
+ - **`smooth_iter`**: Number of iterations for Laplacian smoothing. Default: `0` (none)
73
+ - **`smooth_lamb`**: Strength of each Laplacian smoothing step. Default: `0.2`
74
+ - **`text`**: Custom text used as structural support. Default: `None`
75
+ - **`text2`**: Second line of text. Default: `None`
76
+ - **`textsize`**: Size (height) of the text. Default: `120`
77
+ - **`textback`**: Coronal (depth) position of the back of the text. Default: `300`
78
+ - **`textfront`**: Coronal (depth) position of the front of the text. Default: `330`
79
+ - **`textlinelength`**: Length of line below the text. Default: `10`
80
+
81
+ </details>
82
+
83
+
84
+ ## Command-Line Interface 🖥️
85
+ Process your first brain scan from the terminal by just running
86
+ ```bash
87
+ brain-stl
88
+ ```
89
+ Without providing any arguments, it downloads a publicly available scan and creates a `brain.stl` of it 🧠
90
+
91
+ Run `brain-stl --help` (+copy&paste into ChatGPT) to understand the usage of custom settings 💡
92
+
93
+ ## Share Your Brains 🧠🌐
94
+ Use `create_gif.py` to get a GIF of your model and share it on social media with the hashtag `#brain-stl` 🤗
95
+
@@ -0,0 +1,67 @@
1
+ # brain-stl 🧠
2
+ The **easiest** and **fastest** way to turn brain MRI scans into **3D printable models** 🖨️ powered by [`deepmriprep`](https://github.com/wwu-mmll/deepmriprep) ✨
3
+
4
+ [Use the Colab demo](https://colab.research.google.com/drive/10WSG_qmKnbYrFTwZOlXsIgbda8iz2duQ?usp=sharing) or **install** it locally via `pip install brain_stl` 💨
5
+
6
+ By default, the model is saved as `brain.stl`, but you can customize the filename along with other options like
7
+ - **Threshold**: Pick a value between 0 and 3 for different tissue types (see GIF left, `2.5`: white matter only) 🧠
8
+ - **Hollowness**: Adjust how hollow the brain is (enables faster printing) 💨
9
+ - **Text**: Add personalized text that works as a support structure 🔤
10
+ - **Smoothing**: Achieve a polished surface via iterative Laplacian smoothing ✨
11
+ - **Mesh Reduction**: Simplify the mesh to reduce the size of `brain.stl` ✂️
12
+
13
+ ![gif](https://github.com/user-attachments/assets/64f10b4f-b136-4e86-8ef4-37f9fe0d8fa7)
14
+
15
+ ## Usage 💻
16
+ To get your first `brain.stl` just run
17
+ ```python
18
+ from brain_stl import run_brain_stl
19
+
20
+ run_brain_stl() # per default output_folder='.' (current folder)
21
+ ```
22
+ and a publicly available brain MRI scan (from [OpenNeuro](https://openneuro.org/)) will be used 🌐
23
+
24
+ Scan files can be inputted in NifTi (`.nii` or `.nii.gz`) or DICOM (`.dcm` or [folder](https://pydicom.github.io/pydicom/stable/tutorials/filesets.html)) format
25
+ ```python
26
+ from brain_stl import run_brain_stl
27
+
28
+ run_brain_stl('/path/to/scan.nii.gz') # or '/path/to/dicom_folder'
29
+ ```
30
+ The main arguments of `run_brain_stl` are
31
+ - **`scan_filepath`**: Path to the input scan (if `None`, use scan from `url`). Default: `None`
32
+ - **`output_folder`**: Folder to save the `.stl` file and other outputs. Default: `'.'`
33
+ - **`stl_name`**: Name of the example `.stl` file (without extension). Default: `'brain'`
34
+
35
+ <details>
36
+ <summary><b>Click here</b>, to see <b>all</b> remaining <b>arguments</b> 📑</summary>
37
+
38
+ - **`nifti_name`**: If DICOM produces multiple NifTis, this NifTi filename is used to proceed. Default: `None`
39
+ - **`url`**: URL to download a brain scan if no `scan_filepath` is provided. Default: `OPENNEURO_URL`
40
+ - **`use_cache`**: If `True`, reuses intermediate outputs (e.g., tissue data). Default: `False`
41
+ - **`threshold`**: Threshold tissue value (`0.5`: fluid, `1.5`: gray matter, `2.5`: white matter). Default: `1.5`
42
+ - **`hollow`**: How hollow the brain is (0 to 1). Default: `0`
43
+ - **`in_template_space`**: If `True`, the 3D model is in standardized (template) orientation. Default: `False`
44
+ - **`mesh_reduction`**: Fraction of mesh reduction (0 to 1) for smaller `.stl` file size. Default: `0` (no reduction)
45
+ - **`smooth_iter`**: Number of iterations for Laplacian smoothing. Default: `0` (none)
46
+ - **`smooth_lamb`**: Strength of each Laplacian smoothing step. Default: `0.2`
47
+ - **`text`**: Custom text used as structural support. Default: `None`
48
+ - **`text2`**: Second line of text. Default: `None`
49
+ - **`textsize`**: Size (height) of the text. Default: `120`
50
+ - **`textback`**: Coronal (depth) position of the back of the text. Default: `300`
51
+ - **`textfront`**: Coronal (depth) position of the front of the text. Default: `330`
52
+ - **`textlinelength`**: Length of line below the text. Default: `10`
53
+
54
+ </details>
55
+
56
+
57
+ ## Command-Line Interface 🖥️
58
+ Process your first brain scan from the terminal by just running
59
+ ```bash
60
+ brain-stl
61
+ ```
62
+ Without providing any arguments, it downloads a publicly available scan and creates a `brain.stl` of it 🧠
63
+
64
+ Run `brain-stl --help` (+copy&paste into ChatGPT) to understand the usage of custom settings 💡
65
+
66
+ ## Share Your Brains 🧠🌐
67
+ Use `create_gif.py` to get a GIF of your model and share it on social media with the hashtag `#brain-stl` 🤗
@@ -0,0 +1 @@
1
+ from .main import run_brain_stl
@@ -0,0 +1,47 @@
1
+ import argparse
2
+ from brain_stl.main import OPENNEURO_URL, run_brain_stl
3
+
4
+
5
+ def run_cli():
6
+ parser = argparse.ArgumentParser(description='Generate a 3D STL model of the brain from a scan')
7
+ parser.add_argument('-i', '--scan_filepath', type=str, default=None, help='Path to the input scan (NIfTI or DICOM)')
8
+ parser.add_argument('-o', '--output_folder', type=str, default='.', help='Folder to save the STL file and other outputs')
9
+ parser.add_argument('-n', '--stl_name', type=str, default='brain', help='Name of the example STL file (without extension)')
10
+ parser.add_argument('-ni', '--nifti_name', type=str, help='If DICOM produces multiple NifTis, this NifTi filename is used to proceed')
11
+ parser.add_argument('-u', '--url', type=str, default=OPENNEURO_URL, help='URL to download from if scan_filepath is not provided')
12
+ parser.add_argument('-c', '--use_cache', action='store_true', help='Reuses intermediate outputs (e.g., tissue data)')
13
+ parser.add_argument('-th', '--threshold', type=float, default=1.5, help='Threshold value for brain segmentation (0.5:fluid+gray+white matter, 1.5=gray+white matter, 2.5=white matter)')
14
+ parser.add_argument('-hl', '--hollow', type=float, default=0.0, help='How hollow the brain is (0 to 1)')
15
+ parser.add_argument('-s', '--in_template_space', action='store_true', help='If True, the 3D model is in standardized (template) orientation')
16
+ parser.add_argument('-mr', '--mesh_reduction', type=float, default=0.0, help='Fraction of mesh reduction (0 to 1) for smaller STL file size')
17
+ parser.add_argument('-si', '--smooth_iter', type=int, default=0, help='Number of iterations for Laplacian smoothing')
18
+ parser.add_argument('-sl', '--smooth_lamb', type=float, default=0.2, help='Strength of each Laplacian smoothing step')
19
+ parser.add_argument('-t', '--text', type=str, help='Custom text used as structural support')
20
+ parser.add_argument('-t2', '--text2', type=str, help='Second line of text')
21
+ parser.add_argument('-ts', '--textsize', type=int, default=100, help='Size (height) of the text')
22
+ parser.add_argument('-tb', '--textback', type=int, default=300, help='Coronal (depth) position of the back of the text')
23
+ parser.add_argument('-tf', '--textfront', type=int, default=330, help='Coronal (depth) position of the front of the text')
24
+ parser.add_argument('-tl', '--textlinelength', type=int, default=10, help='Length of line below the text')
25
+ args = parser.parse_args()
26
+ run_brain_stl(scan_filepath=args.scan_filepath,
27
+ output_folder=args.output_folder,
28
+ stl_name=args.stl_name,
29
+ use_cache=args.use_cache,
30
+ hollow=args.hollow,
31
+ text=args.text,
32
+ text2=args.text2,
33
+ textsize=args.textsize,
34
+ textback=args.textback,
35
+ textfront=args.textfront,
36
+ textlinelength=args.textlinelength,
37
+ threshold=args.threshold,
38
+ in_template_space=args.in_template_space,
39
+ mesh_reduction=args.mesh_reduction,
40
+ smooth_iter=args.smooth_iter,
41
+ smooth_lamb=args.smooth_lamb,
42
+ nifti_name=args.nifti_name,
43
+ url=args.url)
44
+
45
+
46
+ if __name__ == '__main__':
47
+ run_cli()
Binary file
@@ -0,0 +1,136 @@
1
+ import trimesh
2
+ import dcm2niix
3
+ import numpy as np
4
+ import pandas as pd
5
+ import nibabel as nib
6
+ import urllib.request
7
+ import fast_simplification
8
+ from pathlib import Path
9
+ from mcubes import marching_cubes
10
+ from deepbet.utils import dilate
11
+ from niftiview import NiftiImageGrid
12
+ from PIL import Image, ImageDraw, ImageFont
13
+ from deepmriprep.preprocess import AFFINE_TEMPLATE, Preprocess
14
+ OPENNEURO_URL = 'https://openneuro.org/crn/datasets/ds000001/snapshots/1.0.0/files/sub-01:anat:sub-01_T1w.nii.gz'
15
+ OUTPUTS = ['affine', 'rotation', 'p0_large']
16
+
17
+
18
+ def run_brain_stl(scan_filepath=None, output_folder='.', stl_name='brain', nifti_name=None, url=OPENNEURO_URL,
19
+ use_cache=False, threshold=1.5, hollow=.0, in_template_space=False, mesh_reduction=.0, smooth_iter=0,
20
+ smooth_lamb=.2, text=None, text2=None, textsize=120, textback=300, textfront=330, textlinelength=10):
21
+ assert Path(output_folder).is_dir(), f'Output folder {output_folder} does not exist'
22
+ if scan_filepath is None:
23
+ print(f'Instead of a scan from disk, using a scan downloaded from {url}')
24
+ nifti_filepath = f'{output_folder}/{url.split(":")[-1]}'
25
+ urllib.request.urlretrieve(url, nifti_filepath)
26
+ else:
27
+ assert Path(str(scan_filepath)).exists(), f'Scan filepath {scan_filepath} does not exist'
28
+ if Path(scan_filepath).is_file() and not scan_filepath.endswith('.dcm'):
29
+ nifti_filepath = scan_filepath
30
+ else:
31
+ nifti_filepath = process_dicom(scan_filepath, output_folder, nifti_name)
32
+ output_paths = {out: f'{output_folder}/{"tissue.nii.gz" if out == "p0_large" else out+".csv"}' for out in OUTPUTS}
33
+ if not use_cache or not all([Path(output_paths[output]).is_file() for output in OUTPUTS]):
34
+ print(f'Calculate and cache (=write to output folder) affine, rotation and tissue of {nifti_filepath}')
35
+ prep = Preprocess()
36
+ prep.run(nifti_filepath, output_paths=output_paths, run_all=False)
37
+ tissue_img = nib.as_closest_canonical(nib.load(output_paths['p0_large']))
38
+ array = tissue_img.get_fdata(dtype=np.float32)
39
+ array = array if hollow == 0 else hollow_out_brain(array, hollow)
40
+ array = array if text is None else add_text(array, text, text2, textsize, textback, textfront, textlinelength)
41
+ vertices, faces = marching_cubes(array, threshold)
42
+ if in_template_space:
43
+ vertices = to_template_space(vertices)
44
+ else:
45
+ vertices = to_scanner_space(vertices, array, nifti_filepath, affine_filepath=output_paths['affine'])
46
+ if mesh_reduction > 0:
47
+ vertices, faces = fast_simplification.simplify(vertices.tolist(), faces.tolist(), mesh_reduction)
48
+ mesh = trimesh.Trimesh(vertices=vertices, faces=faces)
49
+ if smooth_iter > 0:
50
+ print('Smoothing')
51
+ mesh = trimesh.smoothing.filter_laplacian(mesh, lamb=smooth_lamb, iterations=smooth_iter)
52
+ if stl_name is not None:
53
+ mesh.export(f'{output_folder}/{stl_name}.stl')
54
+ return mesh
55
+
56
+
57
+ def process_dicom(scan_filepath, output_folder, nifti_name):
58
+ dcm2niix.main([f'-o', output_folder, scan_filepath])
59
+ nifti_files = sorted(Path.glob(f'{output_folder}/*.ni*'))
60
+ assert len(nifti_files) > 0, f'Scan filepath {scan_filepath} is no valid DICOM'
61
+ if len(nifti_files) > 1:
62
+ im = get_t1w_png(nifti_files)
63
+ im.save(f'{output_folder}/pick_t1w_image.png')
64
+ raise RuntimeError(f'The inputted DICOM {scan_filepath} resulted in {len(nifti_files)} Nifti files.'
65
+ f'View {output_folder}/pick_t1w_image.png, select the filename'
66
+ f'of the appropriate(=T1w) Nifti and pass it via "run_brain_stl(..., nifti_name=*)"')
67
+ return nifti_files[0] if nifti_name is None else [fp for fp in nifti_files if nifti_name in fp][0]
68
+
69
+
70
+ def hollow_out_brain(array, hollow):
71
+ r = int(.3 * (array.shape[0] * array.shape[1] * array.shape[2]) ** (1 / 3))
72
+ hollow_mask = dilate(array > 0, n_layer=int((hollow - 1) * r))
73
+ array[hollow_mask] = 0
74
+ return array
75
+
76
+
77
+ def to_template_space(vertices):
78
+ vertices = AFFINE_TEMPLATE.affine @ np.hstack([vertices, np.ones_like(vertices[:, :1])]).T
79
+ return vertices[:3].T
80
+
81
+
82
+ def to_scanner_space(vertices, array, nifti_filepath, affine_filepath):
83
+ affine = pd.read_csv(affine_filepath).values
84
+ affine = affine[[2, 1, 0, 3]][:, [2, 1, 0, 3]] # undo pytorch zyx ordering
85
+ img = nib.as_closest_canonical(nib.load(nifti_filepath))
86
+ vertices = (2 * vertices / np.array(array.shape)) - 1 # apply pytorch grid scaling [-1;1]
87
+ vertices = (affine @ np.hstack([vertices, np.ones_like(vertices[:, :1])]).T)[:3]
88
+ vertices = .5 * np.array(img.get_fdata().shape) * (vertices.T + 1) # undo pytorch grid scaling [-1;1]
89
+ vertices = img.affine @ np.hstack([vertices, np.ones_like(vertices[:, :1])]).T
90
+ return vertices[:3].T
91
+
92
+
93
+ def add_text(array, text, text2, size, back=300, front=330, linelength=10):
94
+ size = size if text2 is None else size // 2
95
+ textrange = range(back, front)
96
+ height = np.where(array[:, textrange].mean(axis=(0, 1)) > .2)[0][0]
97
+ text_array = get_text_array(text, array.shape[0], size)
98
+ text_left, text_right, text_low, text_up = get_text_bbox(text_array, linelength)
99
+ fontheight = text_up - text_low
100
+ array[:, textrange, height - fontheight:height] += text_array[:, None, text_low:text_up]
101
+ if text2 is None:
102
+ array[text_left:text_right, textrange, 1:height - fontheight + 2] += 3
103
+ else:
104
+ text_array = get_text_array(text2, array.shape[0], size)
105
+ text_left, text_right, text_low, text_up = get_text_bbox(text_array, linelength)
106
+ fontheight2 = text_up - text_low
107
+ array[:, textrange, 1:fontheight2+1] = text_array[:, None, text_low:text_up]
108
+ array[text_left:text_right, textrange, fontheight2+1:height-fontheight+1] += 3
109
+ array[text_left:text_right, textrange, 1:2] += 3
110
+ return array.clip(max=3)
111
+
112
+
113
+ def get_text_array(text, width, height):
114
+ im = Image.new('L', (width, height), color=0)
115
+ d = ImageDraw.Draw(im)
116
+ font = ImageFont.load_default(height)
117
+ d.text((width // 2, 0), text, fill=3, font=font, anchor='mt')
118
+ return np.array(im).T[::-1, ::-1]
119
+
120
+
121
+ def get_text_bbox(array, linelength):
122
+ text_left, text_right = np.where(array.sum(axis=1))[0][[0, -1]]
123
+ text_left = max(0, text_left - linelength - 1)
124
+ text_right = min(text_right + linelength - 1, array.shape[0])
125
+ text_low, text_up = np.where(array.sum(axis=0))[0][[0, -1]]
126
+ return text_left, text_right, text_low, text_up
127
+
128
+
129
+ def get_t1w_png(nifti_files):
130
+ ref_im = Image.open(Path(__file__).parent.resolve() / 'data' / 'ref.png')
131
+ grid_im = NiftiImageGrid(nifti_files).get_image(height=800, layout='sagittal++', fpath=1, fontsize=10)
132
+ ref_im = ref_im.resize((grid_im.size[0], int(ref_im.size[1] * grid_im.size[0] / ref_im.size[0])))
133
+ im = Image.new('L', (ref_im.size[0], ref_im.size[1] + grid_im.size[1]))
134
+ im.paste(ref_im, (0, 0))
135
+ im.paste(grid_im, (0, ref_im.size[1]))
136
+ return im
@@ -0,0 +1,29 @@
1
+ [tool.poetry]
2
+ name = 'brain-stl'
3
+ version = '0.0.1'
4
+ description = 'Turn your brain MRI into a printable 3D model in seconds 🧠➡️🖨️'
5
+ authors = ['codingfisch <l_fisc17@wwu.de>']
6
+ license = 'MIT'
7
+ readme = 'README.md'
8
+ repository = 'https://github.com/codingfisch/brain_stl'
9
+ classifiers = [
10
+ 'Programming Language :: Python :: 3',
11
+ 'Operating System :: OS Independent',
12
+ 'Intended Audience :: Science/Research'
13
+ ]
14
+
15
+ [tool.poetry.dependencies]
16
+ python = '^3.9'
17
+ niftiview = '*'
18
+ deepmriprep = '*'
19
+ trimesh = '*'
20
+ dcm2niix = '*'
21
+ PyMCubes = '*'
22
+ fast_simplification = '0.1.7'
23
+
24
+ [tool.poetry.scripts]
25
+ brain-stl = 'brain_stl.cli:run_cli'
26
+
27
+ [build-system]
28
+ requires = ['poetry-core']
29
+ build-backend = 'poetry.core.masonry.api'