Skip to content

Commit

Permalink
Merge pull request #188 from UKRIN-MAPS/rel/v0.6.1
Browse files Browse the repository at this point in the history
rel/v0.6.1
  • Loading branch information
alexdaniel654 authored Aug 3, 2022
2 parents 25106e0 + d4f23ed commit 640e5f4
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 27 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/python_CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
python-version: [3.7, 3.8, 3.9]
python-version: [3.8, 3.9]

steps:
- uses: actions/checkout@v2
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## [0.6.1] - 2022-08-03

### Added
* Whole kidney segmentation can now be performed using custom models. #187

### Changed
* Python 3.7 is no longer supported.

### Fixed

## [0.6.0] - 2022-02-28

### Added
Expand Down
23 changes: 23 additions & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
cff-version: 1.2.0
message: "If you use this software, please cite it as below."
authors:
- family-names: "Daniel"
given-names: "Alexander J"
orcid: "https://orcid.org/0000-0003-2353-3283"
- family-names: "Nery"
given-names: "Fabio"
orcid: "https://orcid.org/0000-0002-4220-0997"
- family-names: "Almeida e Sousa"
given-names: "Joao"
orcid: "https://orcid.org/0000-0002-6668-7613"
- family-names: "Buchanan"
given-names: "Charlotte E"
orcid: "https://orcid.org/0000-0003-3010-6079"
- family-names: "Francis"
given-names: "Susan T"
orcid: "https://orcid.org/0000-0003-0903-7507"
title: "UKRIN Kidney Analysis Toolbox"
version: 0.6.1
doi: 10.5281/zenodo.4742470
date-released: 2022-08-03
url: "https://github.com/UKRIN-MAPS/ukat"
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ nibabel>=3.0.2
notebook>=6.0.1
numpy>=1.21.2
pandas>=1.3.5
renalsegmentor>=1.3.3
renalsegmentor>=1.3.5
scikit-image>=0.16.2
scipy>=1.7.3
scikit-learn>=1.0.2
Expand Down
5 changes: 2 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@

setup(
name="ukat",
version="0.6.0",
version="0.6.1",
description="UKRIN Kidney Analysis Toolbox",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/UKRIN-MAPS/ukat",
license="GPL-3.0",

python_requires='>=3.7, <4',
python_requires='>=3.8, <4',
packages=find_packages(),
install_requires=requirements,
include_package_data=True,
Expand All @@ -29,7 +29,6 @@
'Topic :: Scientific/Engineering',
'Environment :: Console',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
Expand Down
14 changes: 9 additions & 5 deletions tutorials/segmentation.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@
"We'll start off by getting some test data and doing a basic binary segmentation to categorise each voxel as renal tissue or not renal tissue."
],
"metadata": {
"collapsed": false
"collapsed": false,
"pycharm": {
"name": "#%% md\n"
}
}
},
{
Expand Down Expand Up @@ -82,11 +85,12 @@
"\n",
"# The segmentor needs both the image array and affine so the size of each voxel is known. post_process=True removes all but\n",
"# the largest two areas in the mask e.g. removes small areas of incorrectly categorised tissue. This can cause issues if the\n",
"# subject has more or less than two kidneys though.\n",
"segmentation = whole_kidney.Segmentation(image, affine, post_process=True)\n",
"# subject has more or less than two kidneys though. By default, a binary mask of renal tissue is generated. If the binary\n",
"# flag is set to False, the output will be the probability each voxel is renal tissue.\n",
"segmentation = whole_kidney.Segmentation(image, affine, post_process=True, binary=True)\n",
"\n",
"# A binary mask of renal tissue can be generated. If the binary flag is not used, the output will be the probability each voxel is renal tissue.\n",
"mask = segmentation.get_mask(binary=True)\n",
"# Get the mask as a numpy array\n",
"mask = segmentation.get_mask()\n",
"\n",
"# Display the results\n",
"fig, (ax1, ax2) = plt.subplots(1, 2)\n",
Expand Down
35 changes: 18 additions & 17 deletions ukat/segmentation/whole_kidney.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ class Segmentation(nib.Nifti1Image):
Total, left and right kidney volumes in milliliters.
"""

def __init__(self, pixel_array, affine, post_process=True):
def __init__(self, pixel_array, affine, post_process=True, binary=True,
weights=None):
"""Initialise a whole kidney segmentation class instance.
Parameters
Expand All @@ -29,42 +30,42 @@ def __init__(self, pixel_array, affine, post_process=True):
Keep only the two largest connected volumes in the mask. Note
this may cause issue with subjects that have more or less than
two kidneys.
binary : bool, optional
Default True.
If True, the mask returned will be an array of ints, where 1
represents voxels that are renal tissue and 0 represents
voxels that are not renal tissue. If False, the mask returned
will be the probability that each voxel is renal tissue.
weights : str, optional
Default 'none'.
The path to custom neural network weights. If 'none',
the default, all-purpose, weights will be downloaded from the
internet and used.
"""

super().__init__(pixel_array, affine)
self.pixel_array = pixel_array
self._nifti = nib.Nifti1Image(self.pixel_array, self.affine)
self._seg_obj = Tkv(self._nifti)
self._mask = self._seg_obj.get_mask(post_process=post_process)
self._mask = self._seg_obj.get_mask(post_process=post_process,
binary=binary,
weights_path=weights)
self._kidneys = (self._mask > 0.5) * 1
self._kidneys[:self.shape[0]//2] *= 2
self.volumes = {'total': self._calculate_volume(self._mask > 0.5),
'left': self._calculate_volume(self._kidneys == 1),
'right': self._calculate_volume(self._kidneys == 2)}

def get_mask(self, binary=True):
def get_mask(self):
"""
Returns the estimated mask from the provided input data.
Parameters
----------
binary : bool, optional
Default True.
If True, the mask returned will be an array of bools, where True
represents voxels that are renal tissue and False represents
voxels that are not renal tissue. If False, the mask returned
will be the probability that each voxel is renal tissue.
Returns
-------
mask : np.ndarray
The estimated mask.
"""
if binary:
mask = self._mask > 0.5
else:
mask = self._mask
return mask
return self._mask

def get_kidneys(self):
"""
Expand Down

0 comments on commit 640e5f4

Please sign in to comment.