Skip to content

Commit 73bff0f

Browse files
committed
Added commandline and tests for imagestats volume computation
1 parent d7c7069 commit 73bff0f

File tree

6 files changed

+176
-30
lines changed

6 files changed

+176
-30
lines changed

bin/nib-stats.py

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!python
2+
# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
3+
# vi: set ft=python sts=4 ts=4 sw=4 et:
4+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
5+
#
6+
# See COPYING file distributed along with the NiBabel package for the
7+
# copyright and license terms.
8+
#
9+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
10+
"""
11+
Compute image statistics
12+
"""
13+
14+
from nibabel.cmdline.stats import main
15+
16+
17+
if __name__ == '__main__':
18+
main()

nibabel/cmdline/stats.py

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!python
2+
# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
3+
# vi: set ft=python sts=4 ts=4 sw=4 et:
4+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
5+
#
6+
# See COPYING file distributed along with the NiBabel package for the
7+
# copyright and license terms.
8+
#
9+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
10+
"""
11+
Compute image statistics
12+
"""
13+
14+
import argparse
15+
from nibabel.loadsave import load
16+
from nibabel.imagestats import mask_volume
17+
18+
19+
def _get_parser():
20+
"""Return command-line argument parser."""
21+
p = argparse.ArgumentParser(description=__doc__)
22+
p.add_argument("infile",
23+
help="Neuroimaging volume to compute statistics on.")
24+
p.add_argument("-V", "--Volume", action="store_true", required=False,
25+
help="Compute mask volume of a given mask image.")
26+
p.add_argument("--units", default="mm3", required=False,
27+
help="Preferred output units of {mm3, vox}. Defaults to mm3")
28+
return p
29+
30+
def main(args=None):
31+
"""Main program function."""
32+
parser = _get_parser()
33+
opts = parser.parse_args(args)
34+
from_img = load(opts.infile)
35+
36+
if opts.Volume:
37+
computed_volume = mask_volume(from_img, opts.units)
38+
print(computed_volume)
39+
return computed_volume

nibabel/cmdline/tests/test_stats.py

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!python
2+
# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
3+
# vi: set ft=python sts=4 ts=4 sw=4 et:
4+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
5+
#
6+
# See COPYING file distributed along with the NiBabel package for the
7+
# copyright and license terms.
8+
#
9+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
10+
11+
import unittest
12+
13+
import pytest
14+
15+
from nibabel.testing import test_data
16+
from nibabel.cmdline.stats import main
17+
from nibabel.optpkg import optional_package
18+
19+
_, have_scipy, _ = optional_package('scipy.ndimage')
20+
needs_scipy = unittest.skipUnless(have_scipy, 'These tests need scipy')
21+
22+
23+
def test_volume():
24+
infile = test_data(fname="anatomical.nii")
25+
args = (f"{infile} --Volume")
26+
vol_mm3 = main(args.split())
27+
args = (f"{infile} --Volume --units vox")
28+
vol_vox = main(args.split())
29+
30+
assert float(vol_mm3) == 2273328656.0
31+
assert float(vol_vox) == 284166082.0
32+
33+

nibabel/funcs.py

-30
Original file line numberDiff line numberDiff line change
@@ -216,33 +216,3 @@ def _aff_is_diag(aff):
216216
rzs_aff = aff[:3, :3]
217217
return np.allclose(rzs_aff, np.diag(np.diag(rzs_aff)))
218218

219-
220-
def mask_volume(img):
221-
""" Compute volume of mask image.
222-
Equivalent to "fslstats /path/file.nii -V"
223-
224-
Parameters
225-
----------
226-
img : ``SpatialImage``
227-
All voxels of the mask should be of value 1, background should have value 0.
228-
229-
Returns
230-
-------
231-
mask_volume_mm3: float
232-
Volume of mask expressed in mm3.
233-
234-
Examples
235-
--------
236-
>>> import nibabel as nf
237-
>>> img = nf.load(path) # path is contains a path to an example nifti mask
238-
>>> mask_volume(img)
239-
50.3021
240-
"""
241-
header = img.header
242-
_, vx, vy, vz, _, _, _, _ = header['pixdim']
243-
voxel_volume_mm3 = vx * vy * vz
244-
mask = img.get_fdata()
245-
mask_volume_vx = np.sum(mask)
246-
mask_volume_mm3 = mask_volume_vx * voxel_volume_mm3
247-
248-
return mask_volume_mm3

nibabel/imagestats.py

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
2+
# vi: set ft=python sts=4 ts=4 sw=4 et:
3+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
4+
#
5+
# See COPYING file distributed along with the NiBabel package for the
6+
# copyright and license terms.
7+
#
8+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
9+
"""
10+
Functions for computing image statistics
11+
"""
12+
13+
import numpy as np
14+
15+
16+
def mask_volume(img, units='mm3'):
17+
""" Compute volume of mask image.
18+
Equivalent to "fslstats /path/file.nii -V"
19+
20+
Parameters
21+
----------
22+
img : ``SpatialImage``
23+
All voxels of the mask should be of value 1, background should have value 0.
24+
25+
units : string {"mm3", "vox"}, optional
26+
Unit of the returned mask volume. Defaults to "mm3".
27+
28+
Returns
29+
-------
30+
mask_volume_vx: float
31+
Volume of mask expressed in voxels.
32+
33+
or
34+
35+
mask_volume_mm3: float
36+
Volume of mask expressed in mm3.
37+
38+
Examples
39+
--------
40+
>>> import nibabel as nf
41+
>>> img = nf.load(path) # path is contains a path to an example nifti mask
42+
>>> mask_volume(img)
43+
50.3021
44+
"""
45+
header = img.header
46+
_, vx, vy, vz, _, _, _, _ = header['pixdim']
47+
voxel_volume_mm3 = vx * vy * vz
48+
mask = img.get_fdata()
49+
mask_volume_vx = np.sum(mask)
50+
mask_volume_mm3 = mask_volume_vx * voxel_volume_mm3
51+
52+
if units == 'vox':
53+
return mask_volume_vx
54+
elif units == 'mm3':
55+
return mask_volume_mm3
56+
else:
57+
raise ValueError(f'{units} is not a valid unit. Choose "mm3" or "vox".')

nibabel/tests/test_imagestats.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
2+
# vi: set ft=python sts=4 ts=4 sw=4 et:
3+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
4+
#
5+
# See COPYING file distributed along with the NiBabel package for the
6+
# copyright and license terms.
7+
#
8+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
9+
""" Tests for image statistics """
10+
11+
import numpy as np
12+
13+
from .. import imagestats
14+
from nibabel.testing import test_data
15+
from nibabel.loadsave import load
16+
17+
import pytest
18+
19+
20+
def test_mask_volume():
21+
# Test mask volume computation
22+
infile = test_data(fname="anatomical.nii")
23+
img = load(infile)
24+
vol_mm3 = imagestats.mask_volume(img)
25+
vol_vox = imagestats.mask_volume(img, units='vox')
26+
27+
assert float(vol_mm3) == 2273328656.0
28+
assert float(vol_vox) == 284166082.0
29+

0 commit comments

Comments
 (0)