Reading and Writing Access using Nibabel

What is this pakcage ?

  • It provides read write acees to commonly used Neuroimaging files which includes many formats

Installation

  • Use pip install nibabel

Test installaiton

  • Use import nibabel; nibabel.(__version__);print('succeeded!')

Run builtin test

  • import nibabel; nibabel.test()

Start working

  • Import and use its exposed version nibabel.(__version__)

  • Reading a nifti file. nibabel.load(<filename>)

  • A file that is read is used in a variabel say anat_img = nibabel.load('sample.nii.gz'). This object knows the file shape and image affine ( array matrix) shape. Another attribute is dataobj that gives you the detail of where this object is pointing to.

  • The ouput of nibabel loaded object is an instance of nibabel.nifti1.Nifti1Image which get read in a memory. When it is printed it gives you the address as well for example 0x7fdbdc86b2e0..

  • One can see that the super class is of nibabel.nifti1. This class exposes number of ...file

  • The nibabel attribute dataobj is an object that point to an image array that get loaded.,it is of nibabel.arrayproxy.ArrayProxy ojbect.

  • Array proxies and proxy images are the techniques nibabel uses to load an image from disk, an array proxy is not the array itself but something that represents the array and can provide the array when we load it. It allows us to create the image object withou immediately loading all the array data from sik.

  • Proxy is used rightly because images with an proxy object like this one are called proxy images because the image data is the proxy points to the array data on disk.

  • To check if it is a proxy, nib.is_proxy(anat_img)

  • Image shape and affine shape can be found out using numpy object and to do so you need to get an object that points to an image.

  • And it is done using img_data = anat_img.get_fdata()). This method returns a numpy array object. Its shape attribute will give the same result as nibiabel object.

Start reading ( loading ) an image.

In [7]:
import nibabel as nib 
img = nib.load('data/oxf/ExBox1/STRUCT0001.nii.gz')

# gets its attribute
print(img.shape)            # it will use (img.header.get_data_shape())
print(img.affine.shape)    # 
print(img.dataobj)
header = img.header
print(header)
print(header.get_data_shape())
print(header.get_data_dtype())
print(header.get_zooms()) # voxel in milimiter, and the time between scans in ms, it is the lst value.
(192, 256, 256)
(4, 4)
<nibabel.arrayproxy.ArrayProxy object at 0x7f1493ccc2b0>
<class 'nibabel.nifti1.Nifti1Header'> object, endian='<'
sizeof_hdr      : 348
data_type       : b''
db_name         : b''
extents         : 0
session_error   : 0
regular         : b'r'
dim_info        : 0
dim             : [  3 192 256 256   1   1   1   1]
intent_p1       : 0.0
intent_p2       : 0.0
intent_p3       : 0.0
intent_code     : none
datatype        : int16
bitpix          : 16
slice_start     : 0
pixdim          : [-1.         1.0500001  1.         1.         5.         0.
  0.         0.       ]
vox_offset      : 0.0
scl_slope       : nan
scl_inter       : nan
slice_end       : 0
slice_code      : unknown
xyzt_units      : 10
cal_max         : 1218.0
cal_min         : 0.0
slice_duration  : 0.0
toffset         : 0.0
glmax           : 0
glmin           : 0
descrip         : b'5.0.10'
aux_file        : b''
qform_code      : scanner
sform_code      : scanner
quatern_b       : 0.0
quatern_c       : 1.0
quatern_d       : 0.0
qoffset_x       : 103.30165
qoffset_y       : -119.3996
qoffset_z       : -128.21066
srow_x          : [ -1.0500001   0.          0.        103.30165  ]
srow_y          : [   0.        1.        0.     -119.3996]
srow_z          : [   0.         0.         1.      -128.21066]
intent_name     : b''
magic           : b'n+1'
(192, 256, 256)
int16
(1.0500001, 1.0, 1.0)
In [ ]:
> Most of the header information are not directly accessebile but retrieved  by using  getter `obj.get_dtype()` etc.

Image data

  • An image array can also be stored in the image object as numpy array.
  • To get more about image data, we can get a handle to dataobj that is returned by this function image_data = img.get-fdata(). It is a numpy.ndarray object that represents the data object.
  • Image data object contains all the information that we can directly retrieved by using an image header object. It is another way to represent the data. For example header.get_dtype() will give same result as img_data.dtype.
In [12]:
import nibabel as nib
anat_img = nib.load('data/oxf/ExBox1/STRUCT0001.nii.gz')
anat_img_data = anat_img.get_fdata()

print(type(anat_img_data))
print("*********************************")
print(anat_img_data)
print("*********************************")

print(anat_img_data.shape)
print(anat_img_data.dtype)
<class 'numpy.ndarray'>
*********************************
[[[33. 27. 17. ...  1.  0.  0.]
  [19.  0.  2. ...  0.  0.  0.]
  [29.  4.  5. ...  0.  0.  0.]
  ...
  [17.  2.  5. ...  1.  1.  0.]
  [10.  5. 11. ...  1.  1.  0.]
  [ 0.  0.  0. ...  0.  0.  0.]]

 [[11. 20.  7. ...  1.  0.  0.]
  [11. 18. 10. ...  0.  0.  0.]
  [10.  4.  5. ...  1.  1.  0.]
  ...
  [14. 15.  7. ...  0.  1.  0.]
  [ 7. 12. 11. ...  1.  1.  0.]
  [ 0.  0.  0. ...  0.  0.  0.]]

 [[ 7.  4. 18. ...  1.  0.  0.]
  [ 3.  4. 20. ...  1.  1.  0.]
  [ 9.  7. 22. ...  0.  1.  0.]
  ...
  [14. 13.  9. ...  1.  1.  0.]
  [ 5.  5. 15. ...  1.  0.  0.]
  [ 0.  0.  0. ...  0.  0.  0.]]

 ...

 [[16. 17.  9. ...  0.  0.  0.]
  [19. 14.  8. ...  1.  0.  0.]
  [30. 15. 15. ...  1.  0.  0.]
  ...
  [ 0.  9.  5. ...  0.  0.  0.]
  [ 0.  6. 10. ...  1.  0.  0.]
  [ 0.  0.  0. ...  0.  0.  0.]]

 [[23. 16. 16. ...  1.  0.  0.]
  [10. 28. 24. ...  0.  0.  0.]
  [ 1. 12. 15. ...  0.  1.  0.]
  ...
  [ 7. 11. 16. ...  1.  1.  0.]
  [11.  1.  5. ...  0.  1.  0.]
  [ 0.  0.  0. ...  0.  0.  0.]]

 [[20. 27.  3. ...  1.  0.  0.]
  [21. 22. 24. ...  0.  0.  0.]
  [ 0. 19. 44. ...  0.  0.  0.]
  ...
  [15.  4.  7. ...  0.  0.  0.]
  [12.  4.  4. ...  1.  0.  0.]
  [ 0.  0.  0. ...  0.  0.  0.]]]
*********************************
(192, 256, 256)
float64
In [32]:
# As we saw, that the retruned data object is of `numpy.ndarry `. We can also create an image of `numpy arrays` 
import numpy as np
array_data = np.arange(24, dtype=np.int16)
print(array_data)

print ("*------------------------*")
array_data = array_data.reshape(2,3,4)
print(array_data)
print ("*------------------------*")
affine = np.diag([1,2,3,1])
print(affine)
array_img = nib.Nifti1Image(array_data,affine)
print(array_img)
print(array_img.dataobj)
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
*------------------------*
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
*------------------------*
[[1 0 0 0]
 [0 2 0 0]
 [0 0 3 0]
 [0 0 0 1]]
<class 'nibabel.nifti1.Nifti1Image'>
data shape (2, 3, 4)
affine: 
[[1. 0. 0. 0.]
 [0. 2. 0. 0.]
 [0. 0. 3. 0.]
 [0. 0. 0. 1.]]
metadata:
<class 'nibabel.nifti1.Nifti1Header'> object, endian='<'
sizeof_hdr      : 348
data_type       : b''
db_name         : b''
extents         : 0
session_error   : 0
regular         : b''
dim_info        : 0
dim             : [3 2 3 4 1 1 1 1]
intent_p1       : 0.0
intent_p2       : 0.0
intent_p3       : 0.0
intent_code     : none
datatype        : int16
bitpix          : 16
slice_start     : 0
pixdim          : [1. 1. 2. 3. 1. 1. 1. 1.]
vox_offset      : 0.0
scl_slope       : nan
scl_inter       : nan
slice_end       : 0
slice_code      : unknown
xyzt_units      : 0
cal_max         : 0.0
cal_min         : 0.0
slice_duration  : 0.0
toffset         : 0.0
glmax           : 0
glmin           : 0
descrip         : b''
aux_file        : b''
qform_code      : unknown
sform_code      : aligned
quatern_b       : 0.0
quatern_c       : 0.0
quatern_d       : 0.0
qoffset_x       : 0.0
qoffset_y       : 0.0
qoffset_z       : 0.0
srow_x          : [1. 0. 0. 0.]
srow_y          : [0. 2. 0. 0.]
srow_z          : [0. 0. 3. 0.]
intent_name     : b''
magic           : b'n+1'
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
In [ ]:

checking the data type

  • An image data object can be of array_img.dataobject, farray_img.dataobj
In [14]:
if anat_img_data is array_img.dataobj:
    print("It is of array_img.dataobj")
elif anat_img_data is farray_img.dataobj:
    print("It is of arry_img.dataob")
else:
    print("unknown data dyte")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-14-4c9ab58e1037> in <module>
----> 1 if anat_img_data is array_img.dataobj:
      2     print("It is of array_img.dataobj")
      3 elif anat_img_data is farray_img.dataobj:
      4     print("It is of arry_img.dataob")
      5 else:

NameError: name 'array_img' is not defined
In [ ]:
### Image slicing

-

### Loading and Saving

- 
In [ ]:
import matplotlib.pyplot as plt 
def show_slices(slices):
    ''' Function to desplay row of image slices '''
    fig, axes = plt.subplots(1, len(slices))
    for i, slice in enumerate (slices):
        axes[i].imshow(slice.T, cmap="gray", origin="lower")
    
slice_0 = epi_img_data[96, :, :]
print(len(slice_0))
slice_1 = epi_img_data[:, 128, :]
slice_2 = epi_img_data[:, :, 128]
show_slices([slice_0,slice_1,slice_2])
plt.suptitle("Center slices for EPI image")
In [ ]:
 
In [ ]:
 
In [ ]:
# Get the header of the data
cwd = os.getcwd()
data_dir = cwd + "/data/ds000114/"
print(data_dir)
#print("file header only" + header)

Comments