seqseg 2.1.6__tar.gz → 2.1.8__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.
Files changed (86) hide show
  1. seqseg-2.1.8/PKG-INFO +146 -0
  2. seqseg-2.1.8/README.md +114 -0
  3. {seqseg-2.1.6 → seqseg-2.1.8}/pyproject.toml +2 -4
  4. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/cli.py +141 -59
  5. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/config/global.yaml +1 -0
  6. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/config/global_cereb.yaml +1 -1
  7. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/config/global_debug.yaml +1 -0
  8. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/assembly.py +7 -2
  9. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/nnunet.py +18 -0
  10. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/pipeline/post.py +53 -34
  11. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/pipeline/train.py +627 -82
  12. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_cli_helpers.py +195 -11
  13. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_nnunet_device.py +16 -1
  14. seqseg-2.1.8/seqseg/tests/test_train_data.py +95 -0
  15. seqseg-2.1.8/seqseg/tests/test_train_pipeline.py +1082 -0
  16. seqseg-2.1.8/seqseg.egg-info/PKG-INFO +146 -0
  17. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg.egg-info/SOURCES.txt +1 -0
  18. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg.egg-info/requires.txt +1 -3
  19. seqseg-2.1.6/PKG-INFO +0 -177
  20. seqseg-2.1.6/README.md +0 -144
  21. seqseg-2.1.6/seqseg/tests/test_train_pipeline.py +0 -494
  22. seqseg-2.1.6/seqseg.egg-info/PKG-INFO +0 -177
  23. {seqseg-2.1.6 → seqseg-2.1.8}/LICENSE +0 -0
  24. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/__init__.py +0 -0
  25. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/api.py +0 -0
  26. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/citations.py +0 -0
  27. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/config/__init__.py +0 -0
  28. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/config/aorta_tutorial.yaml +0 -0
  29. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/config/global_aorta.yaml +0 -0
  30. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/config/global_coro.yaml +0 -0
  31. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/config/global_default.yaml +0 -0
  32. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/config/global_pulm.yaml +0 -0
  33. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/config/global_seg.yaml +0 -0
  34. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/config/global_test.yaml +0 -0
  35. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/config_models.py +0 -0
  36. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/__init__.py +0 -0
  37. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/capping.py +0 -0
  38. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/centerline.py +0 -0
  39. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/datasets.py +0 -0
  40. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/evaluation.py +0 -0
  41. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/initialization.py +0 -0
  42. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/local_assembly.py +0 -0
  43. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/params.py +0 -0
  44. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/prediction.py +0 -0
  45. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/simvascular.py +0 -0
  46. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/simvascular_contour.py +0 -0
  47. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/sitk_functions.py +0 -0
  48. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/sweep.py +0 -0
  49. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/tracing.py +0 -0
  50. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/tracing_functions.py +0 -0
  51. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/vmtk_functions.py +0 -0
  52. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/modules/vtk_functions.py +0 -0
  53. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/parallel/old_auto_centerline.py +0 -0
  54. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/parallel/parallel_auto_centerline.py +0 -0
  55. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/parallel/parallel_auto_centerline2.py +0 -0
  56. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/parallel/parallel_auto_centerline3.py +0 -0
  57. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/parallel/parallel_auto_centerline4.py +0 -0
  58. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/pipeline/__init__.py +0 -0
  59. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/pipeline/classic.py +0 -0
  60. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/pipeline/config.py +0 -0
  61. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/pipeline/directories.py +0 -0
  62. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/pipeline/plus.py +0 -0
  63. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/pipeline/single_trace.py +0 -0
  64. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/scripts/__init__.py +0 -0
  65. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/scripts/prepare_casx_dataset.py +0 -0
  66. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/scripts/taubin_smooth.py +0 -0
  67. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/seqseg.py +0 -0
  68. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/seqseg_plus.py +0 -0
  69. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/conftest.py +0 -0
  70. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_api_entry.py +0 -0
  71. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_centerline_get_end_points.py +0 -0
  72. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_centerline_gradient.py +0 -0
  73. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_datasets_paths.py +0 -0
  74. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_nnunet2.py +0 -0
  75. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_prepare_casx_dataset.py +0 -0
  76. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_resample_spacing.py +0 -0
  77. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_segmentation.py +0 -0
  78. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_single_trace_staging.py +0 -0
  79. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_start_seg.py +0 -0
  80. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_user_paths.py +0 -0
  81. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/tests/test_vtk.py +0 -0
  82. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg/user_paths.py +0 -0
  83. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg.egg-info/dependency_links.txt +0 -0
  84. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg.egg-info/entry_points.txt +0 -0
  85. {seqseg-2.1.6 → seqseg-2.1.8}/seqseg.egg-info/top_level.txt +0 -0
  86. {seqseg-2.1.6 → seqseg-2.1.8}/setup.cfg +0 -0
seqseg-2.1.8/PKG-INFO ADDED
@@ -0,0 +1,146 @@
1
+ Metadata-Version: 2.4
2
+ Name: seqseg
3
+ Version: 2.1.8
4
+ Summary: A deep learning-based medical image blood vessel tracking and segmentation tool.
5
+ Author-email: Numi Sveinsson Cepero <numi@berkeley.com>
6
+ License: Apache-2.0
7
+ Project-URL: homepage, https://github.com/numisveinsson/SeqSeg
8
+ Project-URL: repository, https://github.com/numisveinsson/SeqSeg
9
+ Keywords: segmentation,deep learning,medical imaging,nnunet,medical image analysis,medical image segmentation,nnU-Net,blood vessel segmentation,vascular segmentation,vascular tracking,seqseg
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Intended Audience :: Healthcare Industry
15
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
+ Classifier: Topic :: Scientific/Engineering :: Image Recognition
17
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
18
+ Requires-Python: >=3.9
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: vtk>9
22
+ Requires-Dist: SimpleITK>2
23
+ Requires-Dist: PyYAML==6.0.3
24
+ Requires-Dist: nnunetv2>=2.5.1
25
+ Requires-Dist: scipy
26
+ Requires-Dist: vascular-segment-sampler>=0.6.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=7; extra == "dev"
29
+ Provides-Extra: viz
30
+ Requires-Dist: matplotlib>=3.5; extra == "viz"
31
+ Dynamic: license-file
32
+
33
+ ![test seqseg without torch build](https://github.com/numisveinsson/SeqSeg/actions/workflows/python-app.yml/badge.svg)
34
+ ![test seqseg build](https://github.com/numisveinsson/SeqSeg/actions/workflows/test.yml/badge.svg)
35
+
36
+ <p align="center">
37
+ <img src="https://raw.githubusercontent.com/numisveinsson/SeqSeg/main/seqseg/assets/seqseg_logo.png" alt="SeqSeg — Sequential Vessel Segmentation" width="480"/><br/>
38
+ <img src="https://raw.githubusercontent.com/numisveinsson/SeqSeg/main/seqseg/assets/coronary.png" alt="Example coronary segmentation (SeqSeg)" width="260"/>
39
+ </p>
40
+
41
+ <h1 align="center">SeqSeg: Sequential Vessel Segmentation and Tracking</h1>
42
+
43
+ <p align="center">
44
+ <b>Automatic tracking and segmentation of blood vessels in CT and MR images using deep learning and geometric tracking.</b>
45
+ </p>
46
+
47
+ <p align="center">
48
+ <a href="https://rdcu.be/dU0wy"><img src="https://img.shields.io/badge/Paper-Annals%20of%20BME-blue" alt="Paper"/></a>
49
+ <a href="https://github.com/numisveinsson/SeqSeg/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-green.svg" alt="License"/></a>
50
+ <a href="https://www.python.org"><img src="https://img.shields.io/badge/Python-3.9%2B-blue.svg" alt="Python 3.9+"/></a>
51
+ </p>
52
+
53
+ ## Why SeqSeg?
54
+
55
+ SeqSeg segments vessels **sequentially**, taking steps along vessel centerlines and detecting bifurcations to grow complete vascular trees from just **1–2 seed points**. By combining local deep-learning predictions (nnU-Net) with geometric tracking, it stays robust across vessel scales — from small coronaries to large aortas.
56
+
57
+ - 🌱 **Minimal supervision** — only 1–2 seed points to initialize
58
+ - 🌿 **Robust bifurcation detection** — automatically follows every branch
59
+ - 🩻 **Multi-modal** — works with CT and MR 3D medical images
60
+ - 📏 **Scalable** — vessels from ~1mm coronaries to ~30mm aortas
61
+ - ✅ **Clinically validated** — coronary, aortic, cerebral, and pulmonary anatomies (pre-trained weights for aorta CT/MR and coronary CT)
62
+ - ⚡ **Fast** — on CPU, about 2–5 minutes for an aorta, 5–15 for a coronary tree, and 10–30 for a cerebral tree. GPU is faster. Details in [Benchmarks](docs/benchmarks.md).
63
+
64
+ A finished case includes a `simvascular/` project you can open directly in SimVascular, with pathlines and contours for every segmented branch.
65
+
66
+ <p align="center">
67
+ <img src="https://raw.githubusercontent.com/numisveinsson/SeqSeg/main/seqseg/assets/mr_model_tracing_fast_shorter.gif" alt="SeqSeg Demo"/><br/>
68
+ <i>Real-time demonstration: automatic segmentation of an abdominal aorta in a 3D MR scan.</i>
69
+ </p>
70
+
71
+ ## Start here
72
+
73
+ - **First segmentation** — the [tutorial](seqseg/tutorial/tutorial.md) runs a sample abdominal-aorta MR scan.
74
+ - **Your own images** — [Usage](docs/usage.md) describes `images/` and `seeds.json`. The command is in [Quick Start](#quick-start).
75
+ - **Train a model** — [Training](docs/training.md).
76
+
77
+ ## Quick Start
78
+
79
+ Python 3.9 or newer. 3.11 is the version used in the tutorial and conda example.
80
+
81
+ The [tutorial](seqseg/tutorial/tutorial.md) is the sample run (abdominal-aorta MR, seed points, and Windows notes). Plan on 15–20 minutes including setup. Tracing is capped, so that part finishes in a few minutes; a real case should use the defaults.
82
+
83
+ Install SeqSeg and the aorta weights below, then run `seqseg run batch` on your own data. The folder needs `images/` and `seeds.json` ([Usage](docs/usage.md)). This example is an aorta MR case. Change `-train_dataset`, `-config_name`, and `-img_ext` to match your images and weights.
84
+
85
+ ```bash
86
+ pip install seqseg
87
+
88
+ # Aorta and femoral weights (MR and CT)
89
+ curl -L -o nnUNet_results.zip https://zenodo.org/records/15020477/files/nnUNet_results.zip
90
+ unzip nnUNet_results.zip
91
+ ```
92
+
93
+ [Aorta and femoral weights](https://zenodo.org/records/15020477) (`nnUNet_results.zip`). [Coronary CT weights](https://zenodo.org/records/19547894) are a separate archive, `nnUNet_results_coronary.zip`.
94
+
95
+ `-nnunet_results_path` is the folder that contains `Dataset005_SEQAORTANDFEMOMR` (and the other dataset folders in that zip).
96
+
97
+ ```bash
98
+ seqseg run batch \
99
+ -data_dir your_data/ \
100
+ -nnunet_results_path nnUNet_results/ \
101
+ -train_dataset Dataset005_SEQAORTANDFEMOMR \
102
+ -config_name global_aorta \
103
+ -img_ext .mha \
104
+ -outdir results/
105
+ ```
106
+
107
+ | Anatomy | `-train_dataset` | `-config_name` |
108
+ |---------|------------------|----------------|
109
+ | Aorta / femoral MR | `Dataset005_SEQAORTANDFEMOMR` | `global_aorta` |
110
+ | Aorta / femoral CT | `Dataset006_SEQAORTANDFEMOCT` | `global_aorta` |
111
+ | Coronary CT | `Dataset010_SEQCOROASOCACT` | `global_coro` |
112
+
113
+ The tutorial uses `-config_name aorta_tutorial` for its sample scan. The trainer-folder layout is in [Installation](docs/installation.md). The full command list and flag spelling are in [Usage](docs/usage.md).
114
+
115
+ ## Documentation
116
+
117
+ | Job | Guide | Description |
118
+ |-----|-------|-------------|
119
+ | Run | [Installation](docs/installation.md) | Setup, dependencies, and pre-trained model weights |
120
+ | Run | [Tutorial](seqseg/tutorial/tutorial.md) | End-to-end aorta example with sample data |
121
+ | Run | [Usage](docs/usage.md) | Data layout, seeds, CLI arguments, and output files |
122
+ | Run | [Configuration](docs/configuration.md) | YAML configs and tracking parameters |
123
+ | Train | [Training](docs/training.md) | Train nnU-Net models on a new dataset |
124
+ | Understand | [Algorithm Overview](docs/algorithm.md) | Methodology, workflow, and training strategy |
125
+ | Understand | [Performance & Benchmarks](docs/benchmarks.md) | Accuracy, timing, and qualitative comparisons |
126
+ | Integrate | [API](docs/api.md) | Call tracing from Python |
127
+ | Integrate | [Research & Development](docs/development.md) | SimVascular, 3D Slicer, and repository layout |
128
+
129
+ ## Citation
130
+
131
+ When using SeqSeg, please cite the following [paper](https://rdcu.be/dU0wy):
132
+
133
+ ```
134
+ @Article{SveinssonCepero2024,
135
+ author={Sveinsson Cepero, Numi
136
+ and Shadden, Shawn C.},
137
+ title={SeqSeg: Learning Local Segments for Automatic Vascular Model Construction},
138
+ journal={Annals of Biomedical Engineering},
139
+ year={2024},
140
+ month={Sep},
141
+ day={18},
142
+ issn={1573-9686},
143
+ doi={10.1007/s10439-024-03611-z},
144
+ url={https://doi.org/10.1007/s10439-024-03611-z},
145
+ }
146
+ ```
seqseg-2.1.8/README.md ADDED
@@ -0,0 +1,114 @@
1
+ ![test seqseg without torch build](https://github.com/numisveinsson/SeqSeg/actions/workflows/python-app.yml/badge.svg)
2
+ ![test seqseg build](https://github.com/numisveinsson/SeqSeg/actions/workflows/test.yml/badge.svg)
3
+
4
+ <p align="center">
5
+ <img src="https://raw.githubusercontent.com/numisveinsson/SeqSeg/main/seqseg/assets/seqseg_logo.png" alt="SeqSeg — Sequential Vessel Segmentation" width="480"/><br/>
6
+ <img src="https://raw.githubusercontent.com/numisveinsson/SeqSeg/main/seqseg/assets/coronary.png" alt="Example coronary segmentation (SeqSeg)" width="260"/>
7
+ </p>
8
+
9
+ <h1 align="center">SeqSeg: Sequential Vessel Segmentation and Tracking</h1>
10
+
11
+ <p align="center">
12
+ <b>Automatic tracking and segmentation of blood vessels in CT and MR images using deep learning and geometric tracking.</b>
13
+ </p>
14
+
15
+ <p align="center">
16
+ <a href="https://rdcu.be/dU0wy"><img src="https://img.shields.io/badge/Paper-Annals%20of%20BME-blue" alt="Paper"/></a>
17
+ <a href="https://github.com/numisveinsson/SeqSeg/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-green.svg" alt="License"/></a>
18
+ <a href="https://www.python.org"><img src="https://img.shields.io/badge/Python-3.9%2B-blue.svg" alt="Python 3.9+"/></a>
19
+ </p>
20
+
21
+ ## Why SeqSeg?
22
+
23
+ SeqSeg segments vessels **sequentially**, taking steps along vessel centerlines and detecting bifurcations to grow complete vascular trees from just **1–2 seed points**. By combining local deep-learning predictions (nnU-Net) with geometric tracking, it stays robust across vessel scales — from small coronaries to large aortas.
24
+
25
+ - 🌱 **Minimal supervision** — only 1–2 seed points to initialize
26
+ - 🌿 **Robust bifurcation detection** — automatically follows every branch
27
+ - 🩻 **Multi-modal** — works with CT and MR 3D medical images
28
+ - 📏 **Scalable** — vessels from ~1mm coronaries to ~30mm aortas
29
+ - ✅ **Clinically validated** — coronary, aortic, cerebral, and pulmonary anatomies (pre-trained weights for aorta CT/MR and coronary CT)
30
+ - ⚡ **Fast** — on CPU, about 2–5 minutes for an aorta, 5–15 for a coronary tree, and 10–30 for a cerebral tree. GPU is faster. Details in [Benchmarks](docs/benchmarks.md).
31
+
32
+ A finished case includes a `simvascular/` project you can open directly in SimVascular, with pathlines and contours for every segmented branch.
33
+
34
+ <p align="center">
35
+ <img src="https://raw.githubusercontent.com/numisveinsson/SeqSeg/main/seqseg/assets/mr_model_tracing_fast_shorter.gif" alt="SeqSeg Demo"/><br/>
36
+ <i>Real-time demonstration: automatic segmentation of an abdominal aorta in a 3D MR scan.</i>
37
+ </p>
38
+
39
+ ## Start here
40
+
41
+ - **First segmentation** — the [tutorial](seqseg/tutorial/tutorial.md) runs a sample abdominal-aorta MR scan.
42
+ - **Your own images** — [Usage](docs/usage.md) describes `images/` and `seeds.json`. The command is in [Quick Start](#quick-start).
43
+ - **Train a model** — [Training](docs/training.md).
44
+
45
+ ## Quick Start
46
+
47
+ Python 3.9 or newer. 3.11 is the version used in the tutorial and conda example.
48
+
49
+ The [tutorial](seqseg/tutorial/tutorial.md) is the sample run (abdominal-aorta MR, seed points, and Windows notes). Plan on 15–20 minutes including setup. Tracing is capped, so that part finishes in a few minutes; a real case should use the defaults.
50
+
51
+ Install SeqSeg and the aorta weights below, then run `seqseg run batch` on your own data. The folder needs `images/` and `seeds.json` ([Usage](docs/usage.md)). This example is an aorta MR case. Change `-train_dataset`, `-config_name`, and `-img_ext` to match your images and weights.
52
+
53
+ ```bash
54
+ pip install seqseg
55
+
56
+ # Aorta and femoral weights (MR and CT)
57
+ curl -L -o nnUNet_results.zip https://zenodo.org/records/15020477/files/nnUNet_results.zip
58
+ unzip nnUNet_results.zip
59
+ ```
60
+
61
+ [Aorta and femoral weights](https://zenodo.org/records/15020477) (`nnUNet_results.zip`). [Coronary CT weights](https://zenodo.org/records/19547894) are a separate archive, `nnUNet_results_coronary.zip`.
62
+
63
+ `-nnunet_results_path` is the folder that contains `Dataset005_SEQAORTANDFEMOMR` (and the other dataset folders in that zip).
64
+
65
+ ```bash
66
+ seqseg run batch \
67
+ -data_dir your_data/ \
68
+ -nnunet_results_path nnUNet_results/ \
69
+ -train_dataset Dataset005_SEQAORTANDFEMOMR \
70
+ -config_name global_aorta \
71
+ -img_ext .mha \
72
+ -outdir results/
73
+ ```
74
+
75
+ | Anatomy | `-train_dataset` | `-config_name` |
76
+ |---------|------------------|----------------|
77
+ | Aorta / femoral MR | `Dataset005_SEQAORTANDFEMOMR` | `global_aorta` |
78
+ | Aorta / femoral CT | `Dataset006_SEQAORTANDFEMOCT` | `global_aorta` |
79
+ | Coronary CT | `Dataset010_SEQCOROASOCACT` | `global_coro` |
80
+
81
+ The tutorial uses `-config_name aorta_tutorial` for its sample scan. The trainer-folder layout is in [Installation](docs/installation.md). The full command list and flag spelling are in [Usage](docs/usage.md).
82
+
83
+ ## Documentation
84
+
85
+ | Job | Guide | Description |
86
+ |-----|-------|-------------|
87
+ | Run | [Installation](docs/installation.md) | Setup, dependencies, and pre-trained model weights |
88
+ | Run | [Tutorial](seqseg/tutorial/tutorial.md) | End-to-end aorta example with sample data |
89
+ | Run | [Usage](docs/usage.md) | Data layout, seeds, CLI arguments, and output files |
90
+ | Run | [Configuration](docs/configuration.md) | YAML configs and tracking parameters |
91
+ | Train | [Training](docs/training.md) | Train nnU-Net models on a new dataset |
92
+ | Understand | [Algorithm Overview](docs/algorithm.md) | Methodology, workflow, and training strategy |
93
+ | Understand | [Performance & Benchmarks](docs/benchmarks.md) | Accuracy, timing, and qualitative comparisons |
94
+ | Integrate | [API](docs/api.md) | Call tracing from Python |
95
+ | Integrate | [Research & Development](docs/development.md) | SimVascular, 3D Slicer, and repository layout |
96
+
97
+ ## Citation
98
+
99
+ When using SeqSeg, please cite the following [paper](https://rdcu.be/dU0wy):
100
+
101
+ ```
102
+ @Article{SveinssonCepero2024,
103
+ author={Sveinsson Cepero, Numi
104
+ and Shadden, Shawn C.},
105
+ title={SeqSeg: Learning Local Segments for Automatic Vascular Model Construction},
106
+ journal={Annals of Biomedical Engineering},
107
+ year={2024},
108
+ month={Sep},
109
+ day={18},
110
+ issn={1573-9686},
111
+ doi={10.1007/s10439-024-03611-z},
112
+ url={https://doi.org/10.1007/s10439-024-03611-z},
113
+ }
114
+ ```
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "seqseg"
7
- version = "2.1.6"
7
+ version = "2.1.8"
8
8
  description = "A deep learning-based medical image blood vessel tracking and segmentation tool."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -42,6 +42,7 @@ dependencies = [
42
42
  "PyYAML==6.0.3",
43
43
  "nnunetv2>=2.5.1",
44
44
  "scipy",
45
+ "vascular-segment-sampler>=0.6.0",
45
46
  ]
46
47
 
47
48
  [project.scripts]
@@ -62,9 +63,6 @@ dev = [
62
63
  viz = [
63
64
  "matplotlib>=3.5",
64
65
  ]
65
- train = [
66
- "vascular-segment-sampler>=0.1.0",
67
- ]
68
66
 
69
67
  [tool.pytest.ini_options]
70
68
  testpaths = ["seqseg/tests"]
@@ -225,7 +225,8 @@ def _validate_trace_batch(ns: argparse.Namespace) -> None:
225
225
  + "\n ".join(missing)
226
226
  + "\n\nMinimal example:\n"
227
227
  " seqseg paths init\n"
228
- " seqseg paths set --data-dir /path/to/dataset --outdir /path/to/out\n"
228
+ " seqseg paths set --nnunet-root ~/nnunet_data "
229
+ "--data-dir /path/to/dataset --outdir /path/to/out\n"
229
230
  " seqseg run batch -img_ext .nii.gz "
230
231
  "-train_dataset Dataset010_SEQCOROASOCACT\n",
231
232
  file=sys.stderr,
@@ -435,9 +436,8 @@ def _cmd_init_dataset(ns: argparse.Namespace) -> None:
435
436
  f" seqseg run batch -data_dir {root}/ -outdir ... -img_ext .nii.gz "
436
437
  "-nnunet_results_path ...\n"
437
438
  "\nNext (train a new model): also fill centerlines/ and truths/, then:\n"
438
- f' pip install "seqseg[train]"\n'
439
439
  f" seqseg paths init --data-dir {root}/ --outdir ~/seqseg_train\n"
440
- " seqseg train prepare --name MYDATA --dataset-number 999 --modality CT\n"
440
+ " seqseg train prepare --name MYDATA --dataset-id 999 --modality CT\n"
441
441
  )
442
442
 
443
443
 
@@ -550,10 +550,7 @@ def _cmd_doctor(ns: argparse.Namespace) -> None:
550
550
  try:
551
551
  importlib.import_module(modname)
552
552
  except ImportError as e:
553
- extra = ""
554
- if modname == "vascular_segment_sampler":
555
- extra = ' — optional; pip install "seqseg[train]"'
556
- print(f" {label}: MISSING ({e}){extra}")
553
+ print(f" {label}: MISSING ({e})")
557
554
  else:
558
555
  print(f" {label}: OK")
559
556
 
@@ -592,19 +589,9 @@ def _cmd_paths_init(ns: argparse.Namespace) -> None:
592
589
 
593
590
 
594
591
  def _cmd_paths_set(ns: argparse.Namespace) -> None:
595
- fields = (
596
- ns.nnunet_root,
597
- ns.nnunet_raw,
598
- ns.nnunet_preprocessed,
599
- ns.nnunet_results,
600
- ns.data_dir,
601
- ns.outdir,
602
- )
603
- if not any(f is not None for f in fields):
592
+ if not ns.nnunet_root:
604
593
  print(
605
- "seqseg paths set: provide at least one of "
606
- "--nnunet-root, --nnunet-raw, --nnunet-preprocessed, "
607
- "--nnunet-results, --data-dir, --outdir",
594
+ "seqseg paths set: --nnunet-root is required",
608
595
  file=sys.stderr,
609
596
  )
610
597
  sys.exit(2)
@@ -647,6 +634,12 @@ def _cmd_paths_export(_ns: argparse.Namespace) -> None:
647
634
 
648
635
 
649
636
  def _cmd_train_prepare(ns: argparse.Namespace) -> None:
637
+ if not ns.preprocess_only and not ns.name:
638
+ print(
639
+ "seqseg train prepare: --name is required",
640
+ file=sys.stderr,
641
+ )
642
+ sys.exit(2)
650
643
  try:
651
644
  result = prepare_training_dataset(
652
645
  data_dir=ns.data_dir,
@@ -669,14 +662,31 @@ def _cmd_train_prepare(ns: argparse.Namespace) -> None:
669
662
  skip_sample=ns.skip_sample,
670
663
  skip_convert=ns.skip_convert,
671
664
  also_test=ns.also_test,
672
- yes=ns.yes,
673
665
  verbose=ns.verbose,
674
666
  img_ext=ns.img_ext,
675
667
  global_volumes=ns.global_volumes,
668
+ keep_extracted=ns.keep_extracted,
669
+ configuration=ns.configuration,
670
+ plans=ns.plans,
671
+ np=ns.np,
672
+ preprocess_only=ns.preprocess_only,
676
673
  )
677
674
  except TrainDependencyError as e:
678
675
  print(str(e), file=sys.stderr)
679
676
  sys.exit(1)
677
+ except FileNotFoundError as e:
678
+ message = str(e)
679
+ if message.startswith("Sampler config"):
680
+ print(message, file=sys.stderr)
681
+ sys.exit(2)
682
+ if "seqseg train prepare" in message:
683
+ print(message, file=sys.stderr)
684
+ sys.exit(1)
685
+ import traceback
686
+
687
+ traceback.print_exc()
688
+ print(f"seqseg train prepare failed: {e}", file=sys.stderr)
689
+ sys.exit(1)
680
690
  except Exception as e: # noqa: BLE001
681
691
  import traceback
682
692
 
@@ -693,8 +703,29 @@ def _cmd_train_prepare(ns: argparse.Namespace) -> None:
693
703
  sys.exit(1)
694
704
 
695
705
  print("\nPrepare complete.")
696
- kind = "Whole volumes" if ns.global_volumes else "Patches"
697
- print(f" {kind}: {result.extracted_dir}")
706
+ if ns.preprocess_only:
707
+ print(
708
+ f" Preprocessed {ns.configuration} from the existing raw dataset."
709
+ )
710
+ elif result.removed_staging:
711
+ print(
712
+ " Extracted volumes were linked into nnU-Net raw and the "
713
+ "temporary folder was removed."
714
+ )
715
+ else:
716
+ kind = "Whole volumes" if ns.global_volumes else "Patches"
717
+ print(f" {kind}: {result.extracted_dir}")
718
+ if not result.preprocessed:
719
+ print(
720
+ " nnU-Net preprocessing was skipped (--skip-convert). "
721
+ "Re-run prepare without --skip-convert before training."
722
+ )
723
+ results = resolve_path("nnunet_results")
724
+ if results:
725
+ print(f" Trained models will be written under: {results}")
726
+ config_flag = ""
727
+ if ns.configuration != "3d_fullres":
728
+ config_flag = f" --configuration {ns.configuration}"
698
729
  for name, path in zip(result.dataset_names, result.dataset_dirs):
699
730
  try:
700
731
  ds_id = dataset_id_from_name(name)
@@ -702,11 +733,12 @@ def _cmd_train_prepare(ns: argparse.Namespace) -> None:
702
733
  ds_id = "?"
703
734
  print(f" nnU-Net dataset: {name}")
704
735
  print(f" path: {path}")
705
- print(
706
- " next:\n"
707
- f" seqseg train nnunet --dataset-id {ds_id} "
708
- "--configuration 3d_fullres --fold 0"
709
- )
736
+ if result.preprocessed:
737
+ print(
738
+ " next:\n"
739
+ f" seqseg train nnunet --dataset-id {ds_id}"
740
+ f"{config_flag} --fold 0"
741
+ )
710
742
 
711
743
 
712
744
  def _cmd_train_nnunet(ns: argparse.Namespace) -> None:
@@ -729,11 +761,10 @@ def _cmd_train_nnunet(ns: argparse.Namespace) -> None:
729
761
  dataset_id,
730
762
  configuration=ns.configuration,
731
763
  fold=ns.fold,
732
- skip_plan=ns.skip_plan,
733
- plan_only=ns.plan_only,
734
- np=ns.np,
735
764
  trainer=ns.trainer,
736
765
  plans=ns.plans,
766
+ cleanup=ns.cleanup,
767
+ continue_training=ns.continue_training,
737
768
  )
738
769
  except Exception as e: # noqa: BLE001
739
770
  print(f"seqseg train nnunet failed: {e}", file=sys.stderr)
@@ -921,8 +952,18 @@ def _build_parser() -> argparse.ArgumentParser:
921
952
  g1 = gcl_sub.add_parser("single", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
922
953
  g1.add_argument("--seg", required=True, type=str)
923
954
  g1.add_argument("--out", required=True, type=str)
924
- g1.add_argument("--seeds-json", required=True, type=str)
925
- g1.add_argument("--case-name", required=True, type=str)
955
+ g1.add_argument(
956
+ "--seeds-json",
957
+ default=None,
958
+ type=str,
959
+ help="Dataset seeds.json. Omit to place one seed in each disconnected body",
960
+ )
961
+ g1.add_argument(
962
+ "--case-name",
963
+ default=None,
964
+ type=str,
965
+ help="Case name in seeds.json. Required when --seeds-json is set",
966
+ )
926
967
  g1.add_argument("--config-name", default=None, type=str)
927
968
  g1.add_argument("--merge-method", default="clean", type=str)
928
969
  g1.add_argument("--directory-data", default=None, type=str)
@@ -932,7 +973,12 @@ def _build_parser() -> argparse.ArgumentParser:
932
973
  g2 = gcl_sub.add_parser("batch", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
933
974
  g2.add_argument("--seg-dir", required=True, type=str)
934
975
  g2.add_argument("--seg-glob", required=True, type=str)
935
- g2.add_argument("--seeds-json", required=True, type=str)
976
+ g2.add_argument(
977
+ "--seeds-json",
978
+ default=None,
979
+ type=str,
980
+ help="Dataset seeds.json. Omit to place one seed in each disconnected body",
981
+ )
936
982
  g2.add_argument("--out-dir", default=None, type=str)
937
983
  g2.add_argument("--config-name", default=None, type=str)
938
984
  g2.add_argument("--merge-method", default="clean", type=str)
@@ -998,7 +1044,7 @@ def _build_parser() -> argparse.ArgumentParser:
998
1044
 
999
1045
  p_prep = train_sub.add_parser(
1000
1046
  "prepare",
1001
- help="Prepare patches or whole volumes and convert to nnU-Net DatasetXXX format",
1047
+ help="Extract volumes, write an nnU-Net dataset, and plan/preprocess",
1002
1048
  formatter_class=argparse.ArgumentDefaultsHelpFormatter,
1003
1049
  )
1004
1050
  p_prep.add_argument(
@@ -1014,22 +1060,27 @@ def _build_parser() -> argparse.ArgumentParser:
1014
1060
  "-outdir",
1015
1061
  default=None,
1016
1062
  type=str,
1017
- help="Directory for extracted patches or whole volumes "
1018
- "(default: seqseg paths outdir, else ./extracted_data/)",
1063
+ help="Optional scratch directory for extracted patches or whole volumes. "
1064
+ "Default: <parent of nnUNet_raw>/_seqseg_extracted, removed after "
1065
+ "conversion. Pass this to keep extracts or resume with --skip-sample.",
1019
1066
  )
1020
1067
  p_prep.add_argument(
1021
1068
  "--name",
1022
1069
  "-name",
1023
- required=True,
1070
+ default=None,
1024
1071
  type=str,
1025
- help="Dataset name stem (e.g. MYDATA → Dataset0XX_MYDATACT)",
1072
+ help="Dataset name stem (e.g. MYDATA → Dataset0XX_MYDATACT). "
1073
+ "Required unless --preprocess-only",
1026
1074
  )
1027
1075
  p_prep.add_argument(
1076
+ "--dataset-id",
1028
1077
  "--dataset-number",
1029
1078
  "-dataset_number",
1079
+ dest="dataset_number",
1030
1080
  required=True,
1031
1081
  type=int,
1032
- help="nnU-Net dataset id (e.g. 999). Incremented per modality if several",
1082
+ help="nnU-Net dataset id to create (e.g. 999). "
1083
+ "Incremented per modality if several",
1033
1084
  )
1034
1085
  p_prep.add_argument(
1035
1086
  "--modality",
@@ -1041,7 +1092,7 @@ def _build_parser() -> argparse.ArgumentParser:
1041
1092
  p_prep.add_argument(
1042
1093
  "--config-name",
1043
1094
  "-config_name",
1044
- default="global",
1095
+ default="default_mm",
1045
1096
  type=str,
1046
1097
  help="Sampler YAML name/path (from vascular-segment-sampler)",
1047
1098
  )
@@ -1050,7 +1101,7 @@ def _build_parser() -> argparse.ArgumentParser:
1050
1101
  default=None,
1051
1102
  type=str,
1052
1103
  help="Write DatasetXXX_* here "
1053
- "(default: seqseg paths nnunet_raw / $nnUNet_raw; else --outdir)",
1104
+ "(default: seqseg paths nnunet_raw / $nnUNet_raw)",
1054
1105
  )
1055
1106
  p_prep.add_argument(
1056
1107
  "--img-ext",
@@ -1101,13 +1152,41 @@ def _build_parser() -> argparse.ArgumentParser:
1101
1152
  action="store_true",
1102
1153
  help="Also convert modality_test folders when present",
1103
1154
  )
1104
- p_prep.add_argument("--yes", action="store_true", help="Non-interactive confirms")
1105
1155
  p_prep.add_argument("--verbose", action="store_true")
1156
+ p_prep.add_argument(
1157
+ "--keep-extracted",
1158
+ action="store_true",
1159
+ help="Keep <nnunet-root>/_seqseg_extracted after conversion into nnUNet_raw",
1160
+ )
1161
+ p_prep.add_argument(
1162
+ "--configuration",
1163
+ default="3d_fullres",
1164
+ choices=["3d_fullres", "2d", "3d_lowres", "3d_cascade_fullres"],
1165
+ help="nnU-Net configuration to preprocess. Default 3d_fullres",
1166
+ )
1167
+ p_prep.add_argument(
1168
+ "--plans",
1169
+ default="nnUNetPlans",
1170
+ type=str,
1171
+ help="nnU-Net plans name (training -p). Default nnUNetPlans",
1172
+ )
1173
+ p_prep.add_argument(
1174
+ "--np",
1175
+ type=int,
1176
+ default=None,
1177
+ help="Processes for nnU-Net preprocessing. Default: --num-cores",
1178
+ )
1179
+ p_prep.add_argument(
1180
+ "--preprocess-only",
1181
+ action="store_true",
1182
+ help="Preprocess another configuration from an existing raw dataset "
1183
+ "and plans file. Does not extract or convert subvolumes",
1184
+ )
1106
1185
  p_prep.set_defaults(_handler=_cmd_train_prepare, img_ext=None)
1107
1186
 
1108
1187
  p_nn = train_sub.add_parser(
1109
1188
  "nnunet",
1110
- help="Run nnUNetv2_plan_and_preprocess and/or nnUNetv2_train",
1189
+ help="Train with nnUNetv2_train (--c continues from the latest checkpoint)",
1111
1190
  formatter_class=argparse.ArgumentDefaultsHelpFormatter,
1112
1191
  )
1113
1192
  p_nn.add_argument(
@@ -1120,13 +1199,13 @@ def _build_parser() -> argparse.ArgumentParser:
1120
1199
  "--dataset-name",
1121
1200
  type=str,
1122
1201
  default=None,
1123
- help="Alternative to --dataset-id (e.g. Dataset0999_MYDATACT)",
1202
+ help="Alternative to --dataset-id (e.g. Dataset999_MYDATACT)",
1124
1203
  )
1125
1204
  p_nn.add_argument(
1126
1205
  "--configuration",
1127
1206
  default="3d_fullres",
1128
1207
  choices=["3d_fullres", "2d", "3d_lowres", "3d_cascade_fullres"],
1129
- help="nnU-Net configuration for preprocessing (-c) and training",
1208
+ help="nnU-Net configuration to train. Default 3d_fullres",
1130
1209
  )
1131
1210
  p_nn.add_argument(
1132
1211
  "--fold",
@@ -1135,23 +1214,21 @@ def _build_parser() -> argparse.ArgumentParser:
1135
1214
  help="Fold to train (0-4 or all)",
1136
1215
  )
1137
1216
  p_nn.add_argument(
1138
- "--skip-plan",
1217
+ "--c",
1218
+ "--continue",
1219
+ dest="continue_training",
1139
1220
  action="store_true",
1140
- help="Skip plan_and_preprocess; only train",
1221
+ help="Continue training from checkpoint_latest.pth (nnU-Net --c)",
1141
1222
  )
1223
+ p_nn.add_argument("--trainer", default="nnUNetTrainer", type=str)
1224
+ p_nn.add_argument("--plans", default="nnUNetPlans", type=str)
1142
1225
  p_nn.add_argument(
1143
- "--plan-only",
1226
+ "--cleanup",
1144
1227
  action="store_true",
1145
- help="Only run plan_and_preprocess",
1228
+ help="After training succeeds, delete this dataset's nnUNet_raw and "
1229
+ "nnUNet_preprocessed folders. Leaves nnUNet_results. "
1230
+ "A later --c run needs that preprocessed data.",
1146
1231
  )
1147
- p_nn.add_argument(
1148
- "--np",
1149
- type=int,
1150
- default=None,
1151
- help="Processes for plan_and_preprocess (-np)",
1152
- )
1153
- p_nn.add_argument("--trainer", default="nnUNetTrainer", type=str)
1154
- p_nn.add_argument("--plans", default="nnUNetPlans", type=str)
1155
1232
  p_nn.set_defaults(_handler=_cmd_train_nnunet)
1156
1233
 
1157
1234
  paths_p = sub.add_parser(
@@ -1194,10 +1271,15 @@ def _build_parser() -> argparse.ArgumentParser:
1194
1271
 
1195
1272
  p_set = paths_sub.add_parser(
1196
1273
  "set",
1197
- help="Update one or more saved paths",
1274
+ help="Update saved paths (requires --nnunet-root)",
1198
1275
  formatter_class=argparse.ArgumentDefaultsHelpFormatter,
1199
1276
  )
1200
- p_set.add_argument("--nnunet-root", default=None, type=str)
1277
+ p_set.add_argument(
1278
+ "--nnunet-root",
1279
+ required=True,
1280
+ type=str,
1281
+ help="Parent directory for nnUNet_raw / preprocessed / results",
1282
+ )
1201
1283
  p_set.add_argument("--nnunet-raw", default=None, type=str)
1202
1284
  p_set.add_argument("--nnunet-preprocessed", default=None, type=str)
1203
1285
  p_set.add_argument("--nnunet-results", default=None, type=str)
@@ -14,6 +14,7 @@ TREE_ANALYSIS: False
14
14
 
15
15
  VOLUME_SIZE_RATIO: 5 # default 5, 5.5 for coronaries, 4 for segs
16
16
  MAGN_RADIUS: 1
17
+ ADD_RADIUS: 0 # mm (keep in mm)
17
18
  MAX_PERC_ENLARGE: 0.3 # if percent of blood in a given volume goes above this, we try enlarging volume, default 0.33 for coronaries
18
19
  MIN_RADIUS: 0.3 # mm (keep in mm)
19
20
  MIN_RES: 6
@@ -2,7 +2,7 @@
2
2
  # True if we have a segmentation, False if we are predicting
3
3
  SEGMENTATION: False # usually False
4
4
 
5
- DEBUG: True
5
+ DEBUG: False
6
6
  DEBUG_STEP: 200
7
7
 
8
8
  ANIMATION: True # to write out animation files