Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
af3da65
Adding qdess bone segmentation model
gattia Dec 2, 2022
fb4d584
Bone seg return all tissues
gattia Dec 2, 2022
b925b39
Import bone model to models sub-module
gattia Dec 2, 2022
9e7bf99
Add bone seg model to models submodeuls namespace
gattia Dec 2, 2022
d71179e
Done super SegModel because not same funcs
gattia Dec 2, 2022
695a575
Dont compile loaded bone seg model
gattia Dec 2, 2022
373d206
fix tuple concatenation syntax
gattia Dec 2, 2022
5c1e475
expand dims for feature layer - use features first
gattia Dec 2, 2022
dfbdb0b
Adding qdess bone segmentation model
gattia Dec 2, 2022
cbd039a
Bone seg return all tissues
gattia Dec 2, 2022
cda4896
Import bone model to models sub-module
gattia Dec 2, 2022
6309433
Add bone seg model to models submodeuls namespace
gattia Dec 2, 2022
2011737
Done super SegModel because not same funcs
gattia Dec 2, 2022
dd92a61
Dont compile loaded bone seg model
gattia Dec 2, 2022
6dd76cc
fix tuple concatenation syntax
gattia Dec 2, 2022
95793ec
expand dims for feature layer - use features first
gattia Dec 2, 2022
288b65b
Merge branch 'bone_seg' of https://github.com/gattia/DOSMA into bone_seg
gattia Dec 2, 2022
3989833
Add comments - update postprocess reshaping
gattia Dec 5, 2022
e6221ae
Merge remote-tracking branch 'refs/remotes/origin/bone_seg' into bone…
gattia Dec 5, 2022
ba97176
Option (Default) get largest connected components
gattia Dec 6, 2022
b368fb5
Update docs, provide option for re-building model
gattia Dec 6, 2022
adcebe3
Updating documentation
gattia Dec 6, 2022
672eb78
Apply linting
gattia Dec 6, 2022
ee10a10
autoformatting code with make
gattia Dec 6, 2022
0950d45
Lint / autoformat
gattia Aug 29, 2023
4db4709
Add bone segs figures
gattia Aug 29, 2023
1c13dd1
stanford_qdess_bone to return uint8 masks
gattia Oct 17, 2023
69c0229
update StanfordQDessBoneINet2D to be flexible on model image size
gattia Apr 12, 2024
565cd3e
Merge branch 'bone_seg' of https://github.com/gattia/DOSMA into bone_seg
gattia Apr 12, 2024
c7d614e
refactor qdess bone seg model
gattia Apr 24, 2024
cce80f8
Add cube model
gattia Apr 24, 2024
d958d1d
Update tensorflow to be > 2.0.0 & remove import keras
gattia Aug 16, 2024
22d6054
Update docs requirements to use same version of h5py ( not < 3)
gattia Aug 16, 2024
751ef0c
Black format updates
gattia Aug 16, 2024
150f44d
update zip to use `strict=True`
gattia Aug 16, 2024
082c8f0
Fix flake8 linting - and add to ignore
gattia Aug 16, 2024
413adb6
Add DS_Store to gitignore
gattia Aug 16, 2024
310b399
update make dev to install pytest
gattia Aug 16, 2024
e6594f1
Revert "update zip to use `strict=True`"
gattia Aug 16, 2024
2ea5c44
update np.int to int
gattia Aug 16, 2024
84cf578
Add medvolume debugging print statements
gattia Aug 16, 2024
dedc05a
Get rid of strict=True for zip. so compatible with python<3.10
gattia Aug 16, 2024
ef0783c
Updating excel writer syntax to use .close vs .save
gattia Aug 16, 2024
b9cf7cf
Update h5py loading data syntax
gattia Aug 16, 2024
732b44a
keep kers version logger - in case we go back to keras in future
gattia Aug 17, 2024
e64a0db
turn np index into tuple
gattia Aug 17, 2024
7e27a16
update readme re: unit test environment variables.
gattia Aug 17, 2024
0e85754
Updating np.bool to be bool b/c np.bool deprecated
gattia Aug 17, 2024
c36d518
Fix deprecated scipy.ndimage.measurements
gattia Aug 17, 2024
7988b87
Update install instructions to install from source.
gattia Aug 17, 2024
f2f6907
Update gitignore to not log nipype logs.
gattia Aug 17, 2024
046e77f
ignore zip() strict=False in flake8 errors
gattia Aug 17, 2024
f352308
Linting updates.
gattia Aug 17, 2024
ae5fcd8
Fixing sni import errors.
gattia Aug 17, 2024
f2b505a
Drop CI testing for python 3.6 and add 3.9/3.10
gattia Aug 17, 2024
d3f5279
Drop CI testing for python 3.6 and add 3.9/3.10
gattia Aug 17, 2024
34f1e1e
Drop CI Documentation for 3.7
gattia Aug 17, 2024
2cec41f
Remove pinned numba & simpleitk from CI
gattia Aug 17, 2024
055f282
update `np.complex` to use builtin `complex`
gattia Aug 18, 2024
327f37e
Flexibly get tensor shapes
gattia Aug 19, 2024
c15a8a4
Update docs to specify we are not python 3.7+
gattia Aug 19, 2024
4b5f3a8
linting
gattia Aug 19, 2024
97bbb31
No codecov for forked repositroy pull request updates
gattia Aug 19, 2024
2063e0c
Update MedicalVolume.to_sitk
gattia Aug 19, 2024
ac65e62
Linting
gattia Aug 19, 2024
7596c2d
Update new sitk tests to use dicom data - thus not to run if data not…
gattia Aug 19, 2024
c222823
Updating DESS T2 to not require Tg & GlArea.
gattia Oct 3, 2024
ac37526
Updating DESS T2 to not require Tg & GlArea.
gattia Oct 3, 2024
2f2b960
Merge branch 'bone_seg' of https://github.com/gattia/DOSMA into bone_seg
gattia Oct 3, 2024
1605c25
fix np round_ import error.
gattia Mar 9, 2025
b24875e
Add plane-specific bone segmentation models for Stanford QDESS
gattia Mar 9, 2025
22053a4
Refactor bone segmentation volume processing
gattia Mar 9, 2025
3663691
Add framework for STAPLE-based multi-plane segmentation
gattia Mar 9, 2025
53e4d4b
Implement STAPLE-based multi-plane bone segmentation with improved ma…
gattia Mar 9, 2025
d7fbf95
Enhance STAPLE-based bone segmentation with configurable parameters a…
gattia Mar 10, 2025
368950e
Update exclusion indices for STAPLE processing in StanfordQDessBoneUN…
gattia Mar 24, 2025
b9751c4
Add verbose logging and extend StanfordQDessBoneUNet2DSTAPLE initiali…
gattia Mar 24, 2025
2475788
Update exclusion indices for axial processing in StanfordQDessBoneUNe…
gattia Mar 25, 2025
7d947ab
Enhance STAPLE processing in StanfordQDessBoneUNet2DSTAPLE class
gattia Apr 1, 2025
e4ea96a
Refactor DICOM file reading to use pydicom.dcmread
gattia Dec 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Keep in sync with setup.cfg and pyproject.toml which is used for source packages.

[flake8]
ignore = W503, E203, B950, B011, B904
ignore = W503, E203, B950, B011, B904, B907, B905
max-line-length = 100
max-complexity = 18
select = B,C,E,F,W,T4,B9
Expand Down
15 changes: 7 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.6", "3.7", "3.8"]
python-version: ["3.7", "3.8", "3.9", "3.10"]

steps:
- uses: actions/checkout@v2
Expand Down Expand Up @@ -43,7 +43,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.6", "3.7", "3.8"]
python-version: ["3.8", "3.9", "3.10"]

steps:
- uses: actions/checkout@v2
Expand Down Expand Up @@ -72,7 +72,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
python-version: ["3.6", "3.7", "3.8"] # there are some issues with numpy multiarray in 3.7
python-version: ["3.7", "3.8", "3.9", "3.10"] # there are some issues with numpy multiarray in 3.7

steps:
- uses: actions/checkout@v2
Expand All @@ -83,15 +83,13 @@ jobs:
python-version: ${{ matrix.python-version }}

- name: Install Dependencies
# there are some issues with numpy multiarray in 3.7, affecting numba 0.54 installation
# SimpleITK 2.1.0 does not support non-orthonormal directions
run: |
python -m pip install --upgrade pip
pip install numba==0.53.1
pip install tensorflow==2.4.1 keras
pip install numba
pip install tensorflow>=2.0.0
pip install torch
pip install sigpy
pip install --upgrade simpleitk==2.0.2
pip install --upgrade simpleitk
make dev
pip install -e '.[dev]'

Expand All @@ -112,6 +110,7 @@ jobs:
make test-cov

- name: Upload to codecov.io
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
uses: codecov/codecov-action@v1
with:
file: ./coverage.xml
Expand Down
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,13 @@ docs/source/generated

# coverage files
.coverage
coverage.xml
coverage.xml

# system files
.DS_Store

#nipype logfiles
stdout.nipype

# ignore "scratch" files used for testing / debugging
**/scratch
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ build-docs:
cd docs && make html

dev:
pip install pytest
pip install black==21.4b2 click==8.0.2 coverage isort flake8 flake8-bugbear flake8-comprehensions
pip install --upgrade mistune==0.8.4 sphinx sphinx-rtd-theme recommonmark m2r2
pip install -r docs/requirements.txt
Expand Down
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ DOSMA is an AI-powered Python library for medical image analysis. This includes,
We hope that this open-source pipeline will be useful for quick anatomy/pathology analysis and will serve as a hub for adding support for analyzing different anatomies and scan sequences.

## Installation
DOSMA requires Python 3.6+. The core module depends on numpy, nibabel, nipype,
DOSMA requires Python 3.7+. The core module depends on numpy, nibabel, nipype,
pandas, pydicom, scikit-image, scipy, PyYAML, and tqdm.

Additional AI features can be unlocked by installing tensorflow and keras. To
Expand All @@ -30,6 +30,24 @@ pip install dosma
pip install dosma[ai]
```

If you would like to install from source - to get the latest versions, or to build for your specific system:

If you would like to install from source then use:

```bash
git clone git@github.com:ad12/DOSMA.git
cd DOSMA
pip install .
```

To get AI support:

```bash
git clone git@github.com:ad12/DOSMA.git
cd DOSMA
pip install '.[ai]'
```

If you would like to contribute to DOSMA, we recommend you clone the repository and
install DOSMA with `pip` in editable mode.

Expand All @@ -41,6 +59,10 @@ make dev
```

To run tests, build documentation and contribute, run
- If Elastix not installed, must indicate this to system by running the following on the commandline:
`export "DOSMA_UNITTEST_DISABLE_ELASTIX=True"`
- If test data not available add:
`export ""DOSMA_UNITTEST_DISABLE_DATA"=True"`
```bash
make autoformat test build-docs
```
Expand Down
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
h5py<3.0.0
h5py
numpy
natsort
nested-lookup
Expand Down
Binary file added docs/source/figures/DOSMA_bone_segs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions dosma/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
from dosma.core.io.format_io import ImageDataFormat
from dosma.core.quant_vals import QuantitativeValueType as QV
from dosma.defaults import preferences
from dosma.models.model_loading_util import SUPPORTED_MODELS, get_model, model_from_config
from dosma.models.seg_model import SegModel
from dosma.models.util import SUPPORTED_MODELS, get_model, model_from_config
from dosma.msk import knee
from dosma.scan_sequences.mri.cones import Cones
from dosma.scan_sequences.mri.cube_quant import CubeQuant
Expand Down Expand Up @@ -134,7 +134,8 @@ def __init__(
if (dicom_path is not None) and (not os.path.isdir(dicom_path)):
if load_path is not None:
warnings.warn(
"Dicom_path {} not found. Will load data from {}".format(dicom_path, load_path)
"Dicom_path {} not found. Will load data from {}".format(dicom_path, load_path),
stacklevel=2,
)
else:
raise NotADirectoryError("{} is not a directory".format(dicom_path))
Expand Down
28 changes: 19 additions & 9 deletions dosma/core/fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ def _format_out_ufuncs(self, _out_ufuncs, _func_nparams):
if len(_out_ufuncs) > _func_nparams:
warnings.warn(
f"len(out_ufuncs)={len(_out_ufuncs)}, but only {_func_nparams} parameters. "
f"Extra ufuncs will be ignored."
f"Extra ufuncs will be ignored.",
stacklevel=2,
)

return _out_ufuncs
Expand Down Expand Up @@ -174,7 +175,7 @@ def fit(self, x, y: Sequence[MedicalVolume], mask=None, copy_headers: bool = Tru
svs = []

if (not isinstance(y, (list, tuple))) or (
not all([isinstance(_y, MedicalVolume) for _y in y])
not all(isinstance(_y, MedicalVolume) for _y in y)
):
raise TypeError("`y` must be sequence of MedicalVolumes.")

Expand Down Expand Up @@ -647,15 +648,17 @@ def __init__(
if y is not None:
warnings.warn(
f"Setting `y` in the constructor can result in significant memory overhead. "
f"Specify `y` in `{type(self).__name__}.fit(y=...)` instead."
f"Specify `y` in `{type(self).__name__}.fit(y=...)` instead.",
stacklevel=2,
)
self._check_y(x, y)
self.y = y

if mask is not None:
warnings.warn(
f"Setting `mask` in the constructor can result in significant memory overhead. "
f"Specify `mask` in `{type(self).__name__}.fit(mask=...)` instead."
f"Specify `mask` in `{type(self).__name__}.fit(mask=...)` instead.",
stacklevel=2,
)
self.mask = mask

Expand Down Expand Up @@ -739,7 +742,7 @@ def fit(self, x=None, y: Sequence[MedicalVolume] = None, mask=None):
return tc_map, r_squared

def _check_y(self, x, y):
if (not isinstance(y, Sequence)) or (not all([isinstance(sv, MedicalVolume) for sv in y])):
if (not isinstance(y, Sequence)) or (not all(isinstance(sv, MedicalVolume) for sv in y)):
raise TypeError("`y` must be list of MedicalVolumes.")

if any(x.device != cpu_device for x in y):
Expand Down Expand Up @@ -844,7 +847,9 @@ def curve_fit(

oob = y_bounds is not None and ((y < y_bounds[0]).any() or (y > y_bounds[1]).any())
if oob:
warnings.warn("Out of bounds values found. Failure in fit will result in np.nan")
warnings.warn(
"Out of bounds values found. Failure in fit will result in np.nan", stacklevel=2
)

y_T = y.T
if p0_seq:
Expand Down Expand Up @@ -963,7 +968,9 @@ def _compute_r2_matrix(_x, _y, _popts):

oob = y_bounds is not None and ((y < y_bounds[0]).any() or (y > y_bounds[1]).any())
if oob:
warnings.warn("Out of bounds values found. Failure in fit will result in np.nan")
warnings.warn(
"Out of bounds values found. Failure in fit will result in np.nan", stacklevel=2
)

fitter = partial(
_polyfit, x=x, deg=deg, y_bounds=y_bounds, rcond=rcond, w=w, eps=eps, xp=xp.__name__
Expand Down Expand Up @@ -1137,7 +1144,7 @@ def _format_p0(p0, param_args, N):
f"`p0` has unknown keys: {extra_keys}. "
f"Function signature has parameters {param_args}."
)
p0_default = {p: 1.0 for p in param_args}
p0_default = {p: 1.0 for p in param_args} # noqa C420
# Update p0_default to keep the parameter keys in order.
p0_default.update(p0)
p0 = p0_default
Expand Down Expand Up @@ -1170,6 +1177,7 @@ def func(t, a, b):
"__fit_mono_exp__ is deprecated since v0.0.12 and will no longer be "
"supported in v0.0.13. Use `curve_fit` instead.",
DeprecationWarning,
stacklevel=2,
)

x = np.asarray(x)
Expand All @@ -1191,6 +1199,7 @@ def __fit_monoexp_tc__(x, ys, tc0, show_pbar=False): # pragma: no cover
"__fit_monoexp_tc__ is deprecated since v0.12 and will no longer be "
"supported in v0.13. Use `curve_fit` instead.",
DeprecationWarning,
stacklevel=2,
)

p0 = (1.0, -1 / tc0)
Expand All @@ -1203,7 +1212,8 @@ def __fit_monoexp_tc__(x, ys, tc0, show_pbar=False): # pragma: no cover
if (y < 0).any() and not warned_negative:
warned_negative = True
warnings.warn(
"Negative values found. Failure in monoexponential fit will result in np.nan"
"Negative values found. Failure in monoexponential fit will result in np.nan",
stacklevel=2,
)

# Skip any negative values or all values that are 0s
Expand Down
4 changes: 2 additions & 2 deletions dosma/core/io/dicom_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,15 +262,15 @@ def load(
)

if self.num_workers:
fn = functools.partial(pydicom.read_file, force=True)
fn = functools.partial(pydicom.dcmread, force=True)
if self.verbose:
dicom_slices = process_map(fn, lstFilesDCM, max_workers=self.num_workers)
else:
with mp.Pool(self.num_workers) as p:
dicom_slices = p.map(fn, lstFilesDCM)
else:
dicom_slices = [
pydicom.read_file(fp, force=True)
pydicom.dcmread(fp, force=True)
for fp in tqdm(lstFilesDCM, disable=not self.verbose)
]

Expand Down
Loading
Loading