Skip to content
Snippets Groups Projects
Commit 72845f6d authored by Michiel Cottaar's avatar Michiel Cottaar
Browse files

added imobj.affine

parent 36d8290f
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id: tags:
# NIfTI images and python
The [`nibabel`](http://nipy.org/nibabel/) module is used to read and write NIfTI
images and also some other medical imaging formats (e.g., ANALYZE, GIFTI,
MINC, MGH). `nibabel` is included within the FSL python environment.
Building upon `nibabel`, the
[`fslpy`](https://users.fmrib.ox.ac.uk/~paulmc/fsleyes/fslpy/latest/) library
contains a number of FSL-specific classes and functions which you may find
useful. But let's start with `nibabel` - `fslpy` is introduced in a different
practical (`advanced_topics/08_fslpy.ipynb`).
## Contents
* [Reading images](#reading-images)
* [Header info](#header-info)
* [Voxel sizes](#voxel-sizes)
* [Coordinate orientations and mappings](#orientation-info)
* [Voxel sizes](#voxel-sizes)
* [Coordinate orientations and mappings](#orientation-info)
* [Writing images](#writing-images)
* [Exercise](#exercise)
---
<a class="anchor" id="reading-images"></a>
## Reading images
It is easy to read an image:
For most neuroimaging dataformats reading an image is as simple as calling `nibabel.load`.
%% Cell type:code id: tags:
```
import numpy as np
import nibabel as nib
import os.path as op
filename = op.expandvars('${FSLDIR}/data/standard/MNI152_T1_1mm.nii.gz')
imobj = nib.load(filename, mmap=False)
# display header object
imhdr = imobj.header
print('header', imhdr)
# extract data (as a numpy array)
imdat = imobj.get_fdata()
print(imdat.shape)
print('data', imdat.shape)
```
%% Cell type:markdown id: tags:
> Make sure you use the full filename, including the `.nii.gz` extension.
> `fslpy` provides FSL-like automatic file suffix detection though.
> We use the `expandvars()` function above to insert the FSLDIR
> environmental variable into our string. This function is
> discussed more fully in the file management practical.
Reading the data off the disk is not done until `get_fdata()` is called.
> Pitfall:
>
> The option `mmap=False` disables memory mapping, which would otherwise be
> invoked for uncompressed NIfTI files but not for compressed files. Since
> some functionality behaves differently on memory mapped objects, it is
> advisable to turn this off unless you specifically want it.
Once the data is read into a numpy array then it is easily manipulated.
> The `get_fdata` method will return floating point data, regardless of the
> underlying image data type. If you want the image data in the type that it
> is stored (e.g. integer ROI labels), then use
> `imdat = np.asanyarray(imobj.dataobj)` instead.
---
<a class="anchor" id="header-info"></a>
## Header info
There are many methods available on the header object - for example, look at
`dir(imhdr)` or `help(imhdr)` or the [nibabel webpage about NIfTI
images](http://nipy.org/nibabel/nifti_images.html)
<a class="anchor" id="voxel-sizes"></a>
### Voxel sizes
Dimensions of the voxels, in mm, can be found from:
%% Cell type:code id: tags:
```
voxsize = imhdr.get_zooms()
print(voxsize)
```
%% Cell type:markdown id: tags:
<a class="anchor" id="orientation-info"></a>
### Coordinate orientations and mappings
Information about the NIfTI qform and sform matrices can be extracted like this:
%% Cell type:code id: tags:
```
sform = imhdr.get_sform()
sformcode = imhdr['sform_code']
qform = imhdr.get_qform()
qformcode = imhdr['qform_code']
print(qformcode)
print(qform)
```
%% Cell type:markdown id: tags:
You can also get both code and matrix together like this:
%% Cell type:code id: tags:
```
affine, code = imhdr.get_qform(coded=True)
print(affine, code)
```
%% Cell type:markdown id: tags:
If you don't want to have to worry about the difference between `qform` and `sform`,
you can just let `nibabel` return what it thinks is the appropriate `affine`:
%% Cell type:code id: tags:
```
print('affine', imobj.affine)
```
%% Cell type:markdown id: tags:
> Note that we access the `affine` attribute from the image object here, not the image header (like above).
> Accessing the affine this way has the advantage that it will also work for data types, where the affine is stored in a different way in the header.
---
<a class="anchor" id="writing-images"></a>
## Writing images
If you have created a modified image by making or modifying a numpy array then
you need to put this into a NIfTI image object in order to save it to a file.
The easiest way to do this is to copy all the header info from an existing
image like this:
%% Cell type:code id: tags:
```
newdata = imdat * imdat
newhdr = imhdr.copy()
newobj = nib.nifti1.Nifti1Image(newdata, None, header=newhdr)
nib.save(newobj, "mynewname.nii.gz")
```
%% Cell type:markdown id: tags:
where `newdata` is the numpy array (the above is a random example only) and
`imhdr` is the existing image header (as above).
> It is possible to also just pass in an affine matrix rather than a
> copied header, but we *strongly* recommend against this if you are
> processing an existing image as otherwise you run the risk of
> swapping the left-right orientation. Those that have used
> `save_avw` in matlab may well have been bitten in this way in the
> past. Therefore, copy a header from one of the input images
> whenever possible, and just use the affine matrix option if you are
> creating an entirely separate image, like a simulation.
If the voxel size of the image is different, then extra modifications will be
required. Take a look at the `fslpy` practical for some extra image
manipulation options, including cropping and resampling
(`advanced_topics/08_fslpy.ipynb`).
---
<a class="anchor" id="exercises"></a>
## Exercise
Write some code to read in a 4D fMRI image (you can find one
[here](http://www.fmrib.ox.ac.uk/~mark/files/av.nii.gz) if you don't have one
handy), calculate the tSNR and then save the 3D result.
> The tSNR of a time series signal is simply its mean divided by its standard
> deviation.
%% Cell type:code id: tags:
```
# Calculate tSNR
```
......
......@@ -16,8 +16,8 @@ practical (`advanced_topics/08_fslpy.ipynb`).
* [Reading images](#reading-images)
* [Header info](#header-info)
* [Voxel sizes](#voxel-sizes)
* [Coordinate orientations and mappings](#orientation-info)
* [Voxel sizes](#voxel-sizes)
* [Coordinate orientations and mappings](#orientation-info)
* [Writing images](#writing-images)
* [Exercise](#exercise)
......@@ -26,7 +26,7 @@ practical (`advanced_topics/08_fslpy.ipynb`).
<a class="anchor" id="reading-images"></a>
## Reading images
It is easy to read an image:
For most neuroimaging dataformats reading an image is as simple as calling `nibabel.load`.
```
import numpy as np
......@@ -37,10 +37,11 @@ imobj = nib.load(filename, mmap=False)
# display header object
imhdr = imobj.header
print('header', imhdr)
# extract data (as a numpy array)
imdat = imobj.get_fdata()
print(imdat.shape)
print('data', imdat.shape)
```
> Make sure you use the full filename, including the `.nii.gz` extension.
......@@ -105,6 +106,13 @@ affine, code = imhdr.get_qform(coded=True)
print(affine, code)
```
If you don't want to have to worry about the difference between `qform` and `sform`,
you can just let `nibabel` return what it thinks is the appropriate `affine`:
```
print('affine', imobj.affine)
```
> Note that we access the `affine` attribute from the image object here, not the image header (like above).
> Accessing the affine this way has the advantage that it will also work for data types, where the affine is stored in a different way in the header.
---
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment