/usr/lib/python3/dist-packages/nibabel/nifti2.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 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | # 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.
#
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
''' Read / write access to NIfTI2 image format
Format described here:
https://www.nitrc.org/forum/message.php?msg_id=3738
'''
import numpy as np
from .analyze import AnalyzeHeader
from .batteryrunners import Report
from .spatialimages import HeaderDataError, ImageFileError
from .nifti1 import Nifti1Header, Nifti1Pair, Nifti1Image
r"""
Header struct from : https://www.nitrc.org/forum/message.php?msg_id=3738
/*! \struct nifti_2_header
\brief Data structure defining the fields in the nifti2 header.
This binary header should be found at the beginning of a valid
NIFTI-2 header file.
*/
/*************************/ /************/
struct nifti_2_header { /* NIFTI-2 usage */ /* offset
/*************************/ /************/
int sizeof_hdr; /*!< MUST be 540 */ /* 0 */
char magic[8] ; /*!< MUST be valid signature. /* 4 */
short datatype; /*!< Defines data type! */ /* 12 */
short bitpix; /*!< Number bits/voxel. */ /* 14 */
int64_t dim[8]; /*!< Data array dimensions.*/ /* 16 */
double intent_p1 ; /*!< 1st intent parameter. */ /* 80 */
double intent_p2 ; /*!< 2nd intent parameter. */ /* 88 */
double intent_p3 ; /*!< 3rd intent parameter. */ /* 96 */
double pixdim[8]; /*!< Grid spacings. */ /* 104 */
int64_t vox_offset; /*!< Offset into .nii file */ /* 168 */
double scl_slope ; /*!< Data scaling: slope. */ /* 176 */
double scl_inter ; /*!< Data scaling: offset. */ /* 184 */
double cal_max; /*!< Max display intensity */ /* 192 */
double cal_min; /*!< Min display intensity */ /* 200 */
double slice_duration;/*!< Time for 1 slice. */ /* 208 */
double toffset; /*!< Time axis shift. */ /* 216 */
int64_t slice_start; /*!< First slice index. */ /* 224 */
int64_t slice_end; /*!< Last slice index. */ /* 232 */
char descrip[80]; /*!< any text you like. */ /* 240 */
char aux_file[24]; /*!< auxiliary filename. */ /* 320 */
int qform_code ; /*!< NIFTI_XFORM_* code. */ /* 344 */
int sform_code ; /*!< NIFTI_XFORM_* code. */ /* 348 */
double quatern_b ; /*!< Quaternion b param. */ /* 352 */
double quatern_c ; /*!< Quaternion c param. */ /* 360 */
double quatern_d ; /*!< Quaternion d param. */ /* 368 */
double qoffset_x ; /*!< Quaternion x shift. */ /* 376 */
double qoffset_y ; /*!< Quaternion y shift. */ /* 384 */
double qoffset_z ; /*!< Quaternion z shift. */ /* 392 */
double srow_x[4] ; /*!< 1st row affine transform. */ /* 400 */
double srow_y[4] ; /*!< 2nd row affine transform. */ /* 432 */
double srow_z[4] ; /*!< 3rd row affine transform. */ /* 464 */
int slice_code ; /*!< Slice timing order. */ /* 496 */
int xyzt_units ; /*!< Units of pixdim[1..4] */ /* 500 */
int intent_code ; /*!< NIFTI_INTENT_* code. */ /* 504 */
char intent_name[16]; /*!< 'name' or meaning of data. */ /* 508 */
char dim_info; /*!< MRI slice ordering. */ /* 524 */
char unused_str[15]; /*!< unused, filled with \0 */ /* 525 */
} ; /**** 540 bytes total ****/
typedef struct nifti_2_header nifti_2_header ;
"""
# nifti2 flat header definition for first 540 bytes
# First number in comments indicates offset in file header in bytes
header_dtd = [
('sizeof_hdr', 'i4'), # 0; must be 540
('magic', 'S4'), # 4; must be 'ni2\0' or 'n+2\0'
('eol_check', 'i1', (4,)), # 8; must be 0D 0A 1A 0A
('datatype', 'i2'), # 12; it's the datatype
('bitpix', 'i2'), # 14; number of bits per voxel
('dim', 'i8', (8,)), # 16; data array dimensions
('intent_p1', 'f8'), # 80; first intent parameter
('intent_p2', 'f8'), # 88; second intent parameter
('intent_p3', 'f8'), # 96; third intent parameter
('pixdim', 'f8', (8,)), # 104; grid spacings (units below)
('vox_offset', 'i8'), # 168; offset to data in image file
('scl_slope', 'f8'), # 176; data scaling slope
('scl_inter', 'f8'), # 184; data scaling intercept
('cal_max', 'f8'), # 192; max display intensity
('cal_min', 'f8'), # 200; min display intensity
('slice_duration', 'f8'), # 208; time for 1 slice
('toffset', 'f8'), # 216; time axis shift
('slice_start', 'i8'), # 224; first slice index
('slice_end', 'i8'), # 232; last slice index
('descrip', 'S80'), # 240; any text
('aux_file', 'S24'), # 320; auxiliary filename
('qform_code', 'i4'), # 344; xform code
('sform_code', 'i4'), # 348; xform code
('quatern_b', 'f8'), # 352; quaternion b param
('quatern_c', 'f8'), # 360; quaternion c param
('quatern_d', 'f8'), # 368; quaternion d param
('qoffset_x', 'f8'), # 376; quaternion x shift
('qoffset_y', 'f8'), # 384; quaternion y shift
('qoffset_z', 'f8'), # 392; quaternion z shift
('srow_x', 'f8', (4,)), # 400; 1st row affine transform
('srow_y', 'f8', (4,)), # 432; 2nd row affine transform
('srow_z', 'f8', (4,)), # 464; 3rd row affine transform
('slice_code', 'i4'), # 496; slice timing order
('xyzt_units', 'i4'), # 500; inits of pixdim[1..4]
('intent_code', 'i4'), # 504; NIFTI intent code
('intent_name', 'S16'), # 508; name or meaning of data
('dim_info', 'u1'), # 524; MRI slice ordering code
('unused_str', 'S15'), # 525; unused, filled with \0
] # total 540
# Full header numpy dtype
header_dtype = np.dtype(header_dtd)
class Nifti2Header(Nifti1Header):
""" Class for NIfTI2 header
NIfTI2 is a slightly simplified variant of NIfTI1 which replaces 32-bit
floats with 64-bit floats, and increases some integer widths to 32 or 64
bits.
"""
template_dtype = header_dtype
pair_vox_offset = 0
single_vox_offset = 544
# Magics for single and pair
pair_magic = b'ni2'
single_magic = b'n+2'
# Size of header in sizeof_hdr field
sizeof_hdr = 540
# Quaternion threshold near 0, based on float64 preicision
quaternion_threshold = -np.finfo(np.float64).eps * 3
def get_data_shape(self):
''' Get shape of data
Examples
--------
>>> hdr = Nifti2Header()
>>> hdr.get_data_shape()
(0,)
>>> hdr.set_data_shape((1,2,3))
>>> hdr.get_data_shape()
(1, 2, 3)
Expanding number of dimensions gets default zooms
>>> hdr.get_zooms()
(1.0, 1.0, 1.0)
Notes
-----
Does not use Nifti1 freesurfer hack for large vectors described in
:meth:`Nifti1Header.set_data_shape`
'''
return AnalyzeHeader.get_data_shape(self)
def set_data_shape(self, shape):
''' Set shape of data
If ``ndims == len(shape)`` then we set zooms for dimensions higher than
``ndims`` to 1.0
Parameters
----------
shape : sequence
sequence of integers specifying data array shape
Notes
-----
Does not apply nifti1 Freesurfer hack for long vectors (see
:meth:`Nifti1Header.set_data_shape`)
'''
AnalyzeHeader.set_data_shape(self, shape)
@classmethod
def default_structarr(klass, endianness=None):
''' Create empty header binary block with given endianness '''
hdr_data = super(Nifti2Header, klass).default_structarr(endianness)
hdr_data['eol_check'] = (13, 10, 26, 10)
return hdr_data
''' Checks only below here '''
@classmethod
def _get_checks(klass):
# Add our own checks
return (super(Nifti2Header, klass)._get_checks() +
(klass._chk_eol_check,))
@staticmethod
def _chk_eol_check(hdr, fix=False):
rep = Report(HeaderDataError)
if np.all(hdr['eol_check'] == (13, 10, 26, 10)):
return hdr, rep
if np.all(hdr['eol_check'] == 0):
rep.problem_level = 20
rep.problem_msg = 'EOL check all 0'
if fix:
hdr['eol_check'] = (13, 10, 26, 10)
rep.fix_msg = 'setting EOL check to 13, 10, 26, 10'
return hdr, rep
rep.problem_level = 40
rep.problem_msg = ('EOL check not 0 or 13, 10, 26, 10; data may be '
'corrupted by EOL conversion')
if fix:
hdr['eol_check'] = (13, 10, 26, 10)
rep.fix_msg = 'setting EOL check to 13, 10, 26, 10'
return hdr, rep
@classmethod
def may_contain_header(klass, binaryblock):
if len(binaryblock) < klass.sizeof_hdr:
return False
hdr_struct = np.ndarray(shape=(), dtype=header_dtype,
buffer=binaryblock[:klass.sizeof_hdr])
bs_hdr_struct = hdr_struct.byteswap()
return 540 in (hdr_struct['sizeof_hdr'], bs_hdr_struct['sizeof_hdr'])
class Nifti2PairHeader(Nifti2Header):
''' Class for NIfTI2 pair header '''
# Signal whether this is single (header + data) file
is_single = False
class Nifti2Pair(Nifti1Pair):
""" Class for NIfTI2 format image, header pair
"""
header_class = Nifti2PairHeader
_meta_sniff_len = header_class.sizeof_hdr
class Nifti2Image(Nifti1Image):
""" Class for single file NIfTI2 format image
"""
header_class = Nifti2Header
_meta_sniff_len = header_class.sizeof_hdr
def load(filename):
""" Load NIfTI2 single or pair image from `filename`
Parameters
----------
filename : str
filename of image to be loaded
Returns
-------
img : Nifti2Image or Nifti2Pair
nifti2 single or pair image instance
Raises
------
ImageFileError
if `filename` doesn't look like nifti2;
IOError
if `filename` does not exist.
"""
try:
img = Nifti2Image.load(filename)
except ImageFileError:
return Nifti2Pair.load(filename)
return img
def save(img, filename):
""" Save NIfTI2 single or pair to `filename`
Parameters
----------
filename : str
filename to which to save image
"""
try:
Nifti2Image.instance_to_filename(img, filename)
except ImageFileError:
Nifti2Pair.instance_to_filename(img, filename)
|