mspdetect 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.
- mspdetect-0.1.0/.github/workflows/release.yml +56 -0
- mspdetect-0.1.0/.github/workflows/testpypi.yml +59 -0
- mspdetect-0.1.0/.github/workflows/tests.yml +32 -0
- mspdetect-0.1.0/.gitignore +136 -0
- mspdetect-0.1.0/.pre-commit-config.yaml +43 -0
- mspdetect-0.1.0/.readthedocs.yml +28 -0
- mspdetect-0.1.0/CHANGELOG.md +39 -0
- mspdetect-0.1.0/CITATION.cff +22 -0
- mspdetect-0.1.0/LICENSE +21 -0
- mspdetect-0.1.0/PKG-INFO +122 -0
- mspdetect-0.1.0/README.md +85 -0
- mspdetect-0.1.0/docs/source/api/batch.rst +16 -0
- mspdetect-0.1.0/docs/source/api/data.rst +16 -0
- mspdetect-0.1.0/docs/source/api/detection.rst +23 -0
- mspdetect-0.1.0/docs/source/api/metrics.rst +6 -0
- mspdetect-0.1.0/docs/source/api/visualization.rst +6 -0
- mspdetect-0.1.0/docs/source/api.rst +11 -0
- mspdetect-0.1.0/docs/source/cli.rst +36 -0
- mspdetect-0.1.0/docs/source/conf.py +77 -0
- mspdetect-0.1.0/docs/source/configuration.rst +6 -0
- mspdetect-0.1.0/docs/source/conventions.rst +119 -0
- mspdetect-0.1.0/docs/source/index.rst +26 -0
- mspdetect-0.1.0/docs/source/visualization.rst +34 -0
- mspdetect-0.1.0/examples/config.example.yaml +40 -0
- mspdetect-0.1.0/pyproject.toml +163 -0
- mspdetect-0.1.0/setup.cfg +4 -0
- mspdetect-0.1.0/src/mspdetect/__init__.py +51 -0
- mspdetect-0.1.0/src/mspdetect/_version.py +24 -0
- mspdetect-0.1.0/src/mspdetect/batch.py +284 -0
- mspdetect-0.1.0/src/mspdetect/cli.py +58 -0
- mspdetect-0.1.0/src/mspdetect/config.py +256 -0
- mspdetect-0.1.0/src/mspdetect/detect.py +197 -0
- mspdetect-0.1.0/src/mspdetect/io.py +174 -0
- mspdetect-0.1.0/src/mspdetect/metrics.py +162 -0
- mspdetect-0.1.0/src/mspdetect/optimize.py +175 -0
- mspdetect-0.1.0/src/mspdetect/plane.py +155 -0
- mspdetect-0.1.0/src/mspdetect/preprocessing.py +181 -0
- mspdetect-0.1.0/src/mspdetect/results.py +229 -0
- mspdetect-0.1.0/src/mspdetect/viz.py +507 -0
- mspdetect-0.1.0/src/mspdetect.egg-info/PKG-INFO +122 -0
- mspdetect-0.1.0/src/mspdetect.egg-info/SOURCES.txt +54 -0
- mspdetect-0.1.0/src/mspdetect.egg-info/dependency_links.txt +1 -0
- mspdetect-0.1.0/src/mspdetect.egg-info/entry_points.txt +2 -0
- mspdetect-0.1.0/src/mspdetect.egg-info/requires.txt +24 -0
- mspdetect-0.1.0/src/mspdetect.egg-info/scm_file_list.json +49 -0
- mspdetect-0.1.0/src/mspdetect.egg-info/scm_version.json +8 -0
- mspdetect-0.1.0/src/mspdetect.egg-info/top_level.txt +1 -0
- mspdetect-0.1.0/tests/conftest.py +103 -0
- mspdetect-0.1.0/tests/test_cli.py +132 -0
- mspdetect-0.1.0/tests/test_config_results.py +97 -0
- mspdetect-0.1.0/tests/test_detect.py +88 -0
- mspdetect-0.1.0/tests/test_metrics.py +97 -0
- mspdetect-0.1.0/tests/test_plane.py +52 -0
- mspdetect-0.1.0/tests/test_preprocessing.py +76 -0
- mspdetect-0.1.0/tests/test_viz.py +75 -0
- mspdetect-0.1.0/uv.lock +2585 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: Build
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [ created ]
|
|
6
|
+
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
name: Build package from source
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
with:
|
|
17
|
+
persist-credentials: false
|
|
18
|
+
fetch-depth: 0
|
|
19
|
+
- name: Install Python 3
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: '3.10'
|
|
23
|
+
- name: Install build tools
|
|
24
|
+
run: |
|
|
25
|
+
python3 -m pip install build --user
|
|
26
|
+
- name: Build package
|
|
27
|
+
run: |
|
|
28
|
+
python3 -m build
|
|
29
|
+
- name: Upload to CI runner
|
|
30
|
+
uses: actions/upload-artifact@v4
|
|
31
|
+
with:
|
|
32
|
+
name: built-package
|
|
33
|
+
path: dist/
|
|
34
|
+
|
|
35
|
+
pypi-publish:
|
|
36
|
+
name: Publish built package on PyPI
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
needs:
|
|
39
|
+
- build
|
|
40
|
+
|
|
41
|
+
# Specifying a GitHub environment is optional, but strongly encouraged
|
|
42
|
+
environment:
|
|
43
|
+
name: pypi
|
|
44
|
+
url: https://pypi.org/p/mspdetect
|
|
45
|
+
permissions:
|
|
46
|
+
# IMPORTANT: this permission is mandatory for Trusted Publishing
|
|
47
|
+
id-token: write
|
|
48
|
+
steps:
|
|
49
|
+
# retrieve your distributions here
|
|
50
|
+
- name: Download from CI runner
|
|
51
|
+
uses: actions/download-artifact@v4
|
|
52
|
+
with:
|
|
53
|
+
name: built-package
|
|
54
|
+
path: dist/
|
|
55
|
+
- name: Publish on PyPI
|
|
56
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: Test Build
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
name: Build package from source
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
with:
|
|
18
|
+
persist-credentials: false
|
|
19
|
+
fetch-depth: 0
|
|
20
|
+
- name: Install Python 3
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: '3.10'
|
|
24
|
+
- name: Install build tools
|
|
25
|
+
run: |
|
|
26
|
+
python3 -m pip install build --user
|
|
27
|
+
- name: Build package
|
|
28
|
+
run: |
|
|
29
|
+
python3 -m build
|
|
30
|
+
- name: Upload to CI runner
|
|
31
|
+
uses: actions/upload-artifact@v4
|
|
32
|
+
with:
|
|
33
|
+
name: built-package
|
|
34
|
+
path: dist/
|
|
35
|
+
|
|
36
|
+
testpypi-publish:
|
|
37
|
+
name: Publish built package on TestPyPI
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
needs:
|
|
40
|
+
- build
|
|
41
|
+
|
|
42
|
+
# Specifying a GitHub environment is optional, but strongly encouraged
|
|
43
|
+
environment:
|
|
44
|
+
name: testpypi
|
|
45
|
+
url: https://test.pypi.org/p/mspdetect
|
|
46
|
+
permissions:
|
|
47
|
+
# IMPORTANT: this permission is mandatory for Trusted Publishing
|
|
48
|
+
id-token: write
|
|
49
|
+
steps:
|
|
50
|
+
# retrieve your distributions here
|
|
51
|
+
- name: Download from CI runner
|
|
52
|
+
uses: actions/download-artifact@v4
|
|
53
|
+
with:
|
|
54
|
+
name: built-package
|
|
55
|
+
path: dist/
|
|
56
|
+
- name: Publish on PyPI
|
|
57
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
58
|
+
with:
|
|
59
|
+
repository-url: https://test.pypi.org/legacy/
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
pull-requests: write # to post the coverage comment on PRs
|
|
13
|
+
contents: write # to store coverage data/badge on a branch
|
|
14
|
+
strategy:
|
|
15
|
+
matrix:
|
|
16
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 0 # setuptools_scm needs the tags
|
|
21
|
+
- uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
- run: pip install -e ".[dev, viz]"
|
|
25
|
+
- run: ruff check src tests
|
|
26
|
+
- run: ruff format --check src tests
|
|
27
|
+
- run: pytest --cov=mspdetect
|
|
28
|
+
- name: Coverage comment
|
|
29
|
+
if: matrix.python-version == '3.12' # report once, not four times
|
|
30
|
+
uses: py-cov-action/python-coverage-comment-action@v3
|
|
31
|
+
with:
|
|
32
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# VS Code
|
|
2
|
+
.vscode/*
|
|
3
|
+
.history/*
|
|
4
|
+
|
|
5
|
+
# Byte-compiled / optimized / DLL files
|
|
6
|
+
__pycache__/
|
|
7
|
+
*.py[cod]
|
|
8
|
+
*$py.class
|
|
9
|
+
|
|
10
|
+
# C extensions
|
|
11
|
+
*.so
|
|
12
|
+
|
|
13
|
+
# Distribution / packaging
|
|
14
|
+
.Python
|
|
15
|
+
build/
|
|
16
|
+
develop-eggs/
|
|
17
|
+
dist/
|
|
18
|
+
downloads/
|
|
19
|
+
eggs/
|
|
20
|
+
.eggs/
|
|
21
|
+
lib/
|
|
22
|
+
lib64/
|
|
23
|
+
parts/
|
|
24
|
+
sdist/
|
|
25
|
+
var/
|
|
26
|
+
wheels/
|
|
27
|
+
pip-wheel-metadata/
|
|
28
|
+
share/python-wheels/
|
|
29
|
+
*.egg-info/
|
|
30
|
+
.installed.cfg
|
|
31
|
+
*.egg
|
|
32
|
+
MANIFEST
|
|
33
|
+
**/_version.py
|
|
34
|
+
|
|
35
|
+
# PyInstaller
|
|
36
|
+
# Usually these files are written by a python script from a template
|
|
37
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
38
|
+
*.manifest
|
|
39
|
+
*.spec
|
|
40
|
+
|
|
41
|
+
# Installer logs
|
|
42
|
+
pip-log.txt
|
|
43
|
+
pip-delete-this-directory.txt
|
|
44
|
+
|
|
45
|
+
# Unit test / coverage reports
|
|
46
|
+
htmlcov/
|
|
47
|
+
.tox/
|
|
48
|
+
.nox/
|
|
49
|
+
.coverage
|
|
50
|
+
.coverage.*
|
|
51
|
+
.cache
|
|
52
|
+
nosetests.xml
|
|
53
|
+
coverage.xml
|
|
54
|
+
*.cover
|
|
55
|
+
*.py,cover
|
|
56
|
+
.hypothesis/
|
|
57
|
+
.pytest_cache/
|
|
58
|
+
|
|
59
|
+
# Translations
|
|
60
|
+
*.mo
|
|
61
|
+
*.pot
|
|
62
|
+
|
|
63
|
+
# Django stuff:
|
|
64
|
+
*.log
|
|
65
|
+
local_settings.py
|
|
66
|
+
db.sqlite3
|
|
67
|
+
db.sqlite3-journal
|
|
68
|
+
static/
|
|
69
|
+
|
|
70
|
+
# Flask stuff:
|
|
71
|
+
instance/
|
|
72
|
+
.webassets-cache
|
|
73
|
+
|
|
74
|
+
# Scrapy stuff:
|
|
75
|
+
.scrapy
|
|
76
|
+
|
|
77
|
+
# documentation
|
|
78
|
+
docs/_build/
|
|
79
|
+
docs/build/
|
|
80
|
+
pdocs/
|
|
81
|
+
pdoc3/
|
|
82
|
+
docs/jupyter_execute
|
|
83
|
+
|
|
84
|
+
# PyBuilder
|
|
85
|
+
target/
|
|
86
|
+
|
|
87
|
+
# Jupyter Notebook
|
|
88
|
+
.ipynb_checkpoints
|
|
89
|
+
|
|
90
|
+
# IPython
|
|
91
|
+
profile_default/
|
|
92
|
+
ipython_config.py
|
|
93
|
+
|
|
94
|
+
# pyenv
|
|
95
|
+
.python-version
|
|
96
|
+
|
|
97
|
+
# pipenv
|
|
98
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
99
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
100
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
101
|
+
# install all needed dependencies.
|
|
102
|
+
#Pipfile.lock
|
|
103
|
+
|
|
104
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
105
|
+
__pypackages__/
|
|
106
|
+
|
|
107
|
+
# Environments
|
|
108
|
+
.env
|
|
109
|
+
.venv
|
|
110
|
+
env/
|
|
111
|
+
venv/
|
|
112
|
+
ENV/
|
|
113
|
+
env.bak/
|
|
114
|
+
venv.bak/
|
|
115
|
+
.test
|
|
116
|
+
|
|
117
|
+
# Spyder project settings
|
|
118
|
+
.spyderproject
|
|
119
|
+
.spyproject
|
|
120
|
+
|
|
121
|
+
# Rope project settings
|
|
122
|
+
.ropeproject
|
|
123
|
+
|
|
124
|
+
# mkdocs documentation
|
|
125
|
+
/site
|
|
126
|
+
|
|
127
|
+
# mypy
|
|
128
|
+
.mypy_cache/
|
|
129
|
+
.dmypy.json
|
|
130
|
+
dmypy.json
|
|
131
|
+
|
|
132
|
+
# Pyre type checker
|
|
133
|
+
.pyre/
|
|
134
|
+
|
|
135
|
+
# MacOs stuff
|
|
136
|
+
.DS_Store
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
default_install_hook_types: [pre-commit, commit-msg]
|
|
2
|
+
|
|
3
|
+
repos:
|
|
4
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
5
|
+
rev: v5.0.0
|
|
6
|
+
hooks:
|
|
7
|
+
- id: trailing-whitespace
|
|
8
|
+
- id: end-of-file-fixer
|
|
9
|
+
- id: check-merge-conflict
|
|
10
|
+
- id: check-toml
|
|
11
|
+
- id: check-yaml
|
|
12
|
+
- id: check-json
|
|
13
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
14
|
+
rev: v0.12.1
|
|
15
|
+
hooks:
|
|
16
|
+
- id: ruff
|
|
17
|
+
args: [ --fix ]
|
|
18
|
+
- id: ruff-format
|
|
19
|
+
- repo: https://github.com/kynan/nbstripout
|
|
20
|
+
rev: 0.8.1
|
|
21
|
+
hooks:
|
|
22
|
+
- id: nbstripout
|
|
23
|
+
- repo: https://github.com/compilerla/conventional-pre-commit
|
|
24
|
+
rev: v4.2.0
|
|
25
|
+
hooks:
|
|
26
|
+
- id: conventional-pre-commit
|
|
27
|
+
stages: [commit-msg]
|
|
28
|
+
args:
|
|
29
|
+
- build # changes of the build system or dependencies
|
|
30
|
+
- change # commit alters the implementation of an existing feature
|
|
31
|
+
- chore # technical or maintenance task not related to feature or user story
|
|
32
|
+
- ci # edits to the continuous integration scripts/configuration
|
|
33
|
+
- deprecate # a feature or functionality will be deprecated
|
|
34
|
+
- docs # add, update of revise the documentation
|
|
35
|
+
- feat # a new feature was implemented (bump MINOR version)
|
|
36
|
+
- fix # an issue or bug has been fixed (bump PATCH version)
|
|
37
|
+
- perf # performance improvements that do not alter existing behaviour
|
|
38
|
+
- refactor # update shuffles code around but does not alter functionality
|
|
39
|
+
- remove # a feature or functionality is removed
|
|
40
|
+
- style # source code is improved w.r.t. its code quality
|
|
41
|
+
- test # commits enhance or add to the test suite
|
|
42
|
+
- merge # merge one branch into another. Should be ignored by git-chglog
|
|
43
|
+
- revert # revert previous commit(s). Should be ignored by git-chglog
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# .readthedocs.yml
|
|
2
|
+
# Read the Docs configuration file
|
|
3
|
+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
|
4
|
+
|
|
5
|
+
# Required
|
|
6
|
+
version: 2
|
|
7
|
+
|
|
8
|
+
build:
|
|
9
|
+
os: ubuntu-24.04
|
|
10
|
+
tools:
|
|
11
|
+
python: "3.12"
|
|
12
|
+
jobs:
|
|
13
|
+
post_checkout:
|
|
14
|
+
- git fetch --unshallow || true
|
|
15
|
+
|
|
16
|
+
# Build documentation in the docs/ directory with Sphinx
|
|
17
|
+
sphinx:
|
|
18
|
+
builder: html
|
|
19
|
+
configuration: docs/source/conf.py
|
|
20
|
+
fail_on_warning: false
|
|
21
|
+
|
|
22
|
+
# tell RTD to install the package with the docs optional requirements
|
|
23
|
+
python:
|
|
24
|
+
install:
|
|
25
|
+
- method: pip
|
|
26
|
+
path: .
|
|
27
|
+
extra_requirements:
|
|
28
|
+
- docs
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2026-10-26
|
|
6
|
+
|
|
7
|
+
### Documentation
|
|
8
|
+
|
|
9
|
+
- Add documentation.
|
|
10
|
+
- Create changelog.
|
|
11
|
+
|
|
12
|
+
### Miscellaneous Tasks
|
|
13
|
+
|
|
14
|
+
- Update repository URLs after transfer to lycosystem.
|
|
15
|
+
- Add github workflows for publishing.
|
|
16
|
+
|
|
17
|
+
### Refactor
|
|
18
|
+
|
|
19
|
+
- Restructure mspdetect package.
|
|
20
|
+
|
|
21
|
+
### Bug Fixes
|
|
22
|
+
|
|
23
|
+
- Fix imports and logging.
|
|
24
|
+
- Fix bug in widget to correctly visualise sagittal cropping.
|
|
25
|
+
- Fix memory issues.
|
|
26
|
+
- Fix visualisation issues.
|
|
27
|
+
- Adjust optimisation.
|
|
28
|
+
|
|
29
|
+
### Features
|
|
30
|
+
|
|
31
|
+
- Add MSP detection algorithm.
|
|
32
|
+
- Add volume computation of structures.
|
|
33
|
+
- Add more options for cropping.
|
|
34
|
+
- Add possibility to specify patient list.
|
|
35
|
+
- Add possibility to crop shoulders for msp detection.
|
|
36
|
+
- Add configs for checking parameter input.
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
[0.1.0]: https://github.com/lycosystem/mspdetect/releases/tag/0.1.0
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite the article below."
|
|
3
|
+
title: "mspdetect: mid-sagittal plane detection in head and neck planning CTs"
|
|
4
|
+
type: software
|
|
5
|
+
license: MIT
|
|
6
|
+
repository-code: "https://github.com/lycosystem/mspdetect"
|
|
7
|
+
authors:
|
|
8
|
+
- family-names: Keller
|
|
9
|
+
given-names: Loris
|
|
10
|
+
- family-names: Pérez Haas
|
|
11
|
+
given-names: Yoel
|
|
12
|
+
- family-names: Bührer
|
|
13
|
+
given-names: Noemi
|
|
14
|
+
# TODO: fill in once the article is published
|
|
15
|
+
preferred-citation:
|
|
16
|
+
type: article
|
|
17
|
+
title: "TODO: article title"
|
|
18
|
+
authors:
|
|
19
|
+
- family-names: Bührer
|
|
20
|
+
given-names: Noemi
|
|
21
|
+
journal: "TODO"
|
|
22
|
+
year: 2026
|
mspdetect-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Loris Keller, Yoel Pérez Haas, Noemi Bührer
|
|
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.
|
mspdetect-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mspdetect
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Automatic mid-sagittal plane detection in head and neck planning CTs.
|
|
5
|
+
Author: Loris Keller, Yoel Pérez Haas, Noemi Bührer
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: source, https://github.com/lycosystem/mspdetect
|
|
8
|
+
Project-URL: documentation, https://mspdetect.readthedocs.io
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: numpy>=1.24
|
|
16
|
+
Requires-Dist: scipy>=1.10
|
|
17
|
+
Requires-Dist: nibabel>=5.0
|
|
18
|
+
Requires-Dist: pydantic>=2.0
|
|
19
|
+
Requires-Dist: pyyaml>=6.0
|
|
20
|
+
Requires-Dist: tqdm>=4.60
|
|
21
|
+
Provides-Extra: viz
|
|
22
|
+
Requires-Dist: matplotlib>=3.7; extra == "viz"
|
|
23
|
+
Requires-Dist: ipywidgets>=8.0; extra == "viz"
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
26
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
27
|
+
Requires-Dist: ruff>=0.12; extra == "dev"
|
|
28
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
29
|
+
Requires-Dist: git-cliff; extra == "dev"
|
|
30
|
+
Provides-Extra: docs
|
|
31
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
32
|
+
Requires-Dist: sphinx-book-theme; extra == "docs"
|
|
33
|
+
Requires-Dist: myst-parser; extra == "docs"
|
|
34
|
+
Requires-Dist: autodoc_pydantic; extra == "docs"
|
|
35
|
+
Requires-Dist: sphinxcontrib-programoutput; extra == "docs"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# mspdetect
|
|
39
|
+
|
|
40
|
+
Automatic detection of the **mid-sagittal plane (MSP)** in head and neck planning CTs, and
|
|
41
|
+
metrics of structures relative to it (left/right volumes, laterality and distance of the
|
|
42
|
+
tumour to the midline).
|
|
43
|
+
|
|
44
|
+
The plane is found by maximising the left-right symmetry of the bone: bone voxels are mirrored
|
|
45
|
+
across a candidate plane and compared with the CT intensity at the mirrored position.
|
|
46
|
+
|
|
47
|
+
> **Research software.** mspdetect is not a medical device and must not be used for clinical
|
|
48
|
+
> decisions. Always check results visually (see [Visualization](https://mspdetect.readthedocs.io/en/stable/visualization.html)).
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
Requires Python ≥ 3.10.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install "mspdetect[viz] @ git+https://github.com/lycosystem/mspdetect"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`[viz]` adds plotting (matplotlib, ipywidgets) and can be omitted.
|
|
59
|
+
|
|
60
|
+
## Usage
|
|
61
|
+
|
|
62
|
+
### Python
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import mspdetect as msp
|
|
66
|
+
|
|
67
|
+
case = msp.load_case(
|
|
68
|
+
"data/patient01",
|
|
69
|
+
image="CT",
|
|
70
|
+
structures={"GTVp": "ROI__[GTVp]", "Body": "ROI__[EXTERNAL]", "Parotid_L": "ROI__[Parotid_L]"},
|
|
71
|
+
)
|
|
72
|
+
result = msp.detect_msp(case) # default settings, see DetectionConfig
|
|
73
|
+
print(result.plane) # normal and offset in world coordinates
|
|
74
|
+
|
|
75
|
+
metrics = msp.compute_metrics(case, result.plane, structures=["Parotid_L"], target="GTVp")
|
|
76
|
+
msp.save_result(result, "results/patient01") # msp.json + details.npz
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Settings are passed as a `DetectionConfig`, e.g.
|
|
80
|
+
`msp.DetectionConfig(crop={"reference": None})` to use the whole scan.
|
|
81
|
+
|
|
82
|
+
### Command line
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
mspdetect check-config config.yaml # validate and print all settings (incl. defaults)
|
|
86
|
+
mspdetect run config.yaml # detect the plane of all patients
|
|
87
|
+
mspdetect metrics config.yaml # compute metrics from the detected planes
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
See the [command line documentation](https://mspdetect.readthedocs.io/en/stable/cli.html) for the behaviour of the commands and all configuration options.
|
|
91
|
+
|
|
92
|
+
## Inputs and outputs
|
|
93
|
+
|
|
94
|
+
Input are NIfTI files containing the CT in Hounsfield units and, optionally, binary structure masks of the Body, GTVp, or other structures. All volumes are reoriented to RAS+ on loading.
|
|
95
|
+
|
|
96
|
+
The outputs contain the detected plane, objective values along other information such as the package version, settings, etc. Planes are stored in **world coordinates**.
|
|
97
|
+
|
|
98
|
+
When calculating metrics on the detected planes, for each specified structure (`metrics.structures`) a handful of information related to the detected MSP will be determined, e.g. the side, the distance to the MSP, lateral extent, etc.
|
|
99
|
+
|
|
100
|
+
See the [documentation](https://mspdetect.readthedocs.io/en/stable/conventions.html) for further details.
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
## Method
|
|
104
|
+
|
|
105
|
+
1. **Crop** a slab of slices around the reference structure (fixed margins or a fixed-size
|
|
106
|
+
window), optionally extended to the mandible and cropped laterally to exclude the shoulders.
|
|
107
|
+
2. **Bone**: voxels inside `Body` with HU in `hu_range` (default 300–2800).
|
|
108
|
+
3. **Grid search** over the normal's azimuth and polar angle, for planes through the bone's
|
|
109
|
+
centre of mass, scored with the sum of squared differences between each bone voxel and the
|
|
110
|
+
(cubic-interpolated) CT at its mirror position. A robust Huber threshold δ is estimated
|
|
111
|
+
from the residuals (1.345 · 1.4826 · MAD).
|
|
112
|
+
4. **Optimisation** of the Huber loss with BFGS, starting from the best grid plane and using
|
|
113
|
+
the δ of that plane. With `n_starts > 1`, further starts from the next-best grid planes are
|
|
114
|
+
run, each with the δ of its own grid plane. Since these starts minimise different Huber
|
|
115
|
+
losses, the plane with the lowest final quadratic loss (independent of δ) is returned as
|
|
116
|
+
the best, and `first_start_agrees` reports whether the first start reached the same plane
|
|
117
|
+
(within 0.5° and 0.5 mm).
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
## Citation
|
|
121
|
+
|
|
122
|
+
If you use mspdetect, please cite the article in [`CITATION.cff`](https://github.com/lycosystem/mspdetect/blob/main/CITATION.cff).
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# mspdetect
|
|
2
|
+
|
|
3
|
+
Automatic detection of the **mid-sagittal plane (MSP)** in head and neck planning CTs, and
|
|
4
|
+
metrics of structures relative to it (left/right volumes, laterality and distance of the
|
|
5
|
+
tumour to the midline).
|
|
6
|
+
|
|
7
|
+
The plane is found by maximising the left-right symmetry of the bone: bone voxels are mirrored
|
|
8
|
+
across a candidate plane and compared with the CT intensity at the mirrored position.
|
|
9
|
+
|
|
10
|
+
> **Research software.** mspdetect is not a medical device and must not be used for clinical
|
|
11
|
+
> decisions. Always check results visually (see [Visualization](https://mspdetect.readthedocs.io/en/stable/visualization.html)).
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
Requires Python ≥ 3.10.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install "mspdetect[viz] @ git+https://github.com/lycosystem/mspdetect"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`[viz]` adds plotting (matplotlib, ipywidgets) and can be omitted.
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### Python
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
import mspdetect as msp
|
|
29
|
+
|
|
30
|
+
case = msp.load_case(
|
|
31
|
+
"data/patient01",
|
|
32
|
+
image="CT",
|
|
33
|
+
structures={"GTVp": "ROI__[GTVp]", "Body": "ROI__[EXTERNAL]", "Parotid_L": "ROI__[Parotid_L]"},
|
|
34
|
+
)
|
|
35
|
+
result = msp.detect_msp(case) # default settings, see DetectionConfig
|
|
36
|
+
print(result.plane) # normal and offset in world coordinates
|
|
37
|
+
|
|
38
|
+
metrics = msp.compute_metrics(case, result.plane, structures=["Parotid_L"], target="GTVp")
|
|
39
|
+
msp.save_result(result, "results/patient01") # msp.json + details.npz
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Settings are passed as a `DetectionConfig`, e.g.
|
|
43
|
+
`msp.DetectionConfig(crop={"reference": None})` to use the whole scan.
|
|
44
|
+
|
|
45
|
+
### Command line
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
mspdetect check-config config.yaml # validate and print all settings (incl. defaults)
|
|
49
|
+
mspdetect run config.yaml # detect the plane of all patients
|
|
50
|
+
mspdetect metrics config.yaml # compute metrics from the detected planes
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
See the [command line documentation](https://mspdetect.readthedocs.io/en/stable/cli.html) for the behaviour of the commands and all configuration options.
|
|
54
|
+
|
|
55
|
+
## Inputs and outputs
|
|
56
|
+
|
|
57
|
+
Input are NIfTI files containing the CT in Hounsfield units and, optionally, binary structure masks of the Body, GTVp, or other structures. All volumes are reoriented to RAS+ on loading.
|
|
58
|
+
|
|
59
|
+
The outputs contain the detected plane, objective values along other information such as the package version, settings, etc. Planes are stored in **world coordinates**.
|
|
60
|
+
|
|
61
|
+
When calculating metrics on the detected planes, for each specified structure (`metrics.structures`) a handful of information related to the detected MSP will be determined, e.g. the side, the distance to the MSP, lateral extent, etc.
|
|
62
|
+
|
|
63
|
+
See the [documentation](https://mspdetect.readthedocs.io/en/stable/conventions.html) for further details.
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
## Method
|
|
67
|
+
|
|
68
|
+
1. **Crop** a slab of slices around the reference structure (fixed margins or a fixed-size
|
|
69
|
+
window), optionally extended to the mandible and cropped laterally to exclude the shoulders.
|
|
70
|
+
2. **Bone**: voxels inside `Body` with HU in `hu_range` (default 300–2800).
|
|
71
|
+
3. **Grid search** over the normal's azimuth and polar angle, for planes through the bone's
|
|
72
|
+
centre of mass, scored with the sum of squared differences between each bone voxel and the
|
|
73
|
+
(cubic-interpolated) CT at its mirror position. A robust Huber threshold δ is estimated
|
|
74
|
+
from the residuals (1.345 · 1.4826 · MAD).
|
|
75
|
+
4. **Optimisation** of the Huber loss with BFGS, starting from the best grid plane and using
|
|
76
|
+
the δ of that plane. With `n_starts > 1`, further starts from the next-best grid planes are
|
|
77
|
+
run, each with the δ of its own grid plane. Since these starts minimise different Huber
|
|
78
|
+
losses, the plane with the lowest final quadratic loss (independent of δ) is returned as
|
|
79
|
+
the best, and `first_start_agrees` reports whether the first start reached the same plane
|
|
80
|
+
(within 0.5° and 0.5 mm).
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
## Citation
|
|
84
|
+
|
|
85
|
+
If you use mspdetect, please cite the article in [`CITATION.cff`](https://github.com/lycosystem/mspdetect/blob/main/CITATION.cff).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Data loading and preprocessing
|
|
2
|
+
===============================
|
|
3
|
+
|
|
4
|
+
Data Loading
|
|
5
|
+
-------------
|
|
6
|
+
|
|
7
|
+
.. automodule:: mspdetect.io
|
|
8
|
+
:members:
|
|
9
|
+
:show-inheritance:
|
|
10
|
+
|
|
11
|
+
Preprocessing
|
|
12
|
+
--------------
|
|
13
|
+
|
|
14
|
+
.. automodule:: mspdetect.preprocessing
|
|
15
|
+
:members:
|
|
16
|
+
:show-inheritance:
|