Source code for unravel.image_io.nii_info
#!/usr/bin/env python3
"""
Use ``io_nii_info`` (``i``) from UNRAVEL to load an .nii.gz image and print its data type, shape, voxel sizes, and affine matrix.
Usage:
------
i -i path/img.nii.gz [-u] [-v]
"""
import nibabel as nib
import numpy as np
from rich import print
from rich.traceback import install
from unravel.core.config import Configuration
from unravel.core.help_formatter import RichArgumentParser, SuppressMetavar, SM
from unravel.core.img_tools import label_IDs
from unravel.core.utils import log_command, verbose_start_msg, verbose_end_msg
[docs]
def parse_args():
parser = RichArgumentParser(formatter_class=SuppressMetavar, add_help=False, docstring=__doc__)
reqs = parser.add_argument_group('Required arguments')
reqs.add_argument('-i', '--input', help='path/img.nii.gz', action=SM)
opts = parser.add_argument_group('Optional arguments')
opts.add_argument('-u', '--unique', help='Print unique intensities. Default: False', action='store_true', default=False)
opts.add_argument('-v', '--verbose', help='Print volume and intensity info. Default: False', action='store_true', default=False)
return parser.parse_args()
[docs]
def nii_axis_codes(nii):
"""Get and return axes codes (three letter orientation like RAS) from an nibabel NIfTI image"""
axcodes_tuple = nib.orientations.aff2axcodes(nii.affine)
axcodes = ''.join(axcodes_tuple)
return axcodes
[docs]
def main():
install()
args = parse_args()
nii_path = args.input if str(args.input).endswith(".nii.gz") else f"{args.input}.nii.gz"
nii = nib.load(nii_path)
np.set_printoptions(precision=2, suppress=True)
# Print data type
data_type = nii.get_data_dtype()
print(f'\nData type: [default bold]{data_type}')
# Print intensity range
if args.verbose:
img = np.asanyarray(nii.dataobj, dtype=nii.header.get_data_dtype()).squeeze()
max_intensity = img.max()
min_intensity = img.min()
print(f'Intensity range: {min_intensity} to {max_intensity}')
# Print dimensions
print(f'\nShape (x, y, z): {nii.shape}')
# Print the voxel sizes
voxel_sizes = nii.header.get_zooms()
voxel_sizes = tuple(np.array(voxel_sizes) * 1000)
print(f'Voxel sizes (µm): {voxel_sizes}')
# Print number of non-zero voxels and total number of voxels
if args.verbose:
num_nonzero = np.count_nonzero(img)
num_voxels = np.prod(img.shape)
nonzero_volume_in_mm = (voxel_sizes[0] * voxel_sizes[1] * voxel_sizes[2]) * num_nonzero / 1e9
total_volume_in_mm = (voxel_sizes[0] * voxel_sizes[1] * voxel_sizes[2]) * num_voxels / 1e9
print(f'\nNumber of non-zero voxels: {num_nonzero} out of {num_voxels} ([default bold]{num_nonzero / num_voxels:.2%}[/])')
print(f'Volume of non-zero voxels: {nonzero_volume_in_mm:.2f} out of {total_volume_in_mm:.2f} ([default bold]mm^3[/])')
# Print number of unique intensities
if args.unique:
if not 'img' in locals():
img = np.asanyarray(nii.dataobj, dtype=nii.header.get_data_dtype()).squeeze()
uniq_intensities = label_IDs(img, min_voxel_count=1, print_IDs=False, print_sizes=False)
print(f'\nUnique intensities (total: [default bold]{len(uniq_intensities)}):')
uniq_intensities = label_IDs(img, min_voxel_count=1, print_IDs=True, print_sizes=False)
# Print orientation and affine
axcodes = nii_axis_codes(nii)
np.set_printoptions(precision=4, suppress=True)
print(f'\nAffine matrix ([default bold]{axcodes}[/]):\n{nii.affine}\n')
if __name__ == '__main__':
main()