/usr/lib/python3/dist-packages/nibabel/minc2.py is in python3-nibabel 2.2.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | # emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
#
# See COPYING file distributed along with the NiBabel package for the
# copyright and license terms.
#
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
""" Preliminary MINC2 support
Use with care; I haven't tested this against a wide range of MINC files.
If you have a file that isn't read correctly, please send an example.
Test reading with something like::
import nibabel as nib
img = nib.load('my_funny.mnc')
data = img.get_data()
print(data.mean())
print(data.max())
print(data.min())
and compare against command line output of::
mincstats my_funny.mnc
"""
import numpy as np
from .optpkg import optional_package
h5py, have_h5py, setup_module = optional_package('h5py')
from .minc1 import Minc1File, MincHeader, Minc1Image, MincError
class Hdf5Bunch(object):
""" Make object for accessing attributes of variable
"""
def __init__(self, var):
for name, value in var.attrs.items():
setattr(self, name, value)
class Minc2File(Minc1File):
''' Class to wrap MINC2 format file
Although it has some of the same methods as a ``Header``, we use
this only when reading a MINC2 file, to pull out useful header
information, and for the method of reading the data out
'''
def __init__(self, mincfile):
self._mincfile = mincfile
minc_part = mincfile['minc-2.0']
# The whole image is the first of the entries in 'image'
image = minc_part['image']['0']
self._image = image['image']
self._dim_names = self._get_dimensions(self._image)
dimensions = minc_part['dimensions']
self._dims = [Hdf5Bunch(dimensions[s]) for s in self._dim_names]
# We don't currently support irregular spacing
# https://en.wikibooks.org/wiki/MINC/Reference/MINC2.0_File_Format_Reference#Dimension_variable_attributes
for dim in self._dims:
if dim.spacing != b'regular__':
raise ValueError('Irregular spacing not supported')
self._spatial_dims = [name for name in self._dim_names
if name.endswith('space')]
self._image_max = image['image-max']
self._image_min = image['image-min']
def _get_dimensions(self, var):
# Dimensions for a particular variable
# Differs for MINC1 and MINC2 - see:
# https://en.wikibooks.org/wiki/MINC/Reference/MINC2.0_File_Format_Reference#Associating_HDF5_dataspaces_with_MINC_dimensions
try:
dimorder = var.attrs['dimorder'].decode()
except KeyError: # No specified dimensions
return []
# The dimension name list must contain only as many entries
# as the variable has dimensions. This reduces errors when an
# unnecessary dimorder attribute is left behind.
return dimorder.split(',')[:len(var.shape)]
def get_data_dtype(self):
return self._image.dtype
def get_data_shape(self):
return self._image.shape
def _get_valid_range(self):
''' Return valid range for image data
The valid range can come from the image 'valid_range' or
failing that, from the data type range
'''
ddt = self.get_data_dtype()
info = np.iinfo(ddt.type)
try:
valid_range = self._image.attrs['valid_range']
except (AttributeError, KeyError):
valid_range = [info.min, info.max]
else:
if valid_range[0] < info.min or valid_range[1] > info.max:
raise ValueError('Valid range outside input '
'data type range')
return np.asarray(valid_range, dtype=np.float)
def _get_scalar(self, var):
""" Get scalar value from HDF5 scalar """
return var.value
def _get_array(self, var):
""" Get array from HDF5 array """
return np.asanyarray(var)
def get_scaled_data(self, sliceobj=()):
""" Return scaled data for slice definition `sliceobj`
Parameters
----------
sliceobj : tuple, optional
slice definition. If not specified, return whole array
Returns
-------
scaled_arr : array
array from minc file with scaling applied
"""
if sliceobj == ():
raw_data = np.asanyarray(self._image)
else: # Try slicing into the HDF array (maybe it's possible)
try:
raw_data = self._image[sliceobj]
except (ValueError, TypeError):
raw_data = np.asanyarray(self._image)[sliceobj]
else:
raw_data = np.asanyarray(raw_data)
return self._normalize(raw_data, sliceobj)
class Minc2Header(MincHeader):
@classmethod
def may_contain_header(klass, binaryblock):
return binaryblock[:4] == b'\211HDF'
class Minc2Image(Minc1Image):
''' Class for MINC2 images
The MINC2 image class uses the default header type, rather than a
specific MINC header type - and reads the relevant information from
the MINC file on load.
'''
# MINC2 does not do compressed whole files
_compressed_suffixes = ()
header_class = Minc2Header
@classmethod
def from_file_map(klass, file_map):
holder = file_map['image']
if holder.filename is None:
raise MincError('MINC2 needs filename for load')
minc_file = Minc2File(h5py.File(holder.filename, 'r'))
affine = minc_file.get_affine()
if affine.shape != (4, 4):
raise MincError('Image does not have 3 spatial dimensions')
data_dtype = minc_file.get_data_dtype()
shape = minc_file.get_data_shape()
zooms = minc_file.get_zooms()
header = klass.header_class(data_dtype, shape, zooms)
data = klass.ImageArrayProxy(minc_file)
return klass(data, affine, header, extra=None, file_map=file_map)
load = Minc2Image.load
|