library(neurobase)
Note: Throughout this post, I will refer to an image on hard disk as
a NIfTI, which is a file that generally has the extension “.nii” or
“.nii.gz”. I will refer to the object in R as a nifti
(note
the change of font and case).
In this tutorial we will discuss the basics of reading the
nifti
object in R. There are many objects in R that
represent imaging data. The Neuroconductor project chose the
nifti
object from the oro.nifti
package as one
of the the basic building blocks because it has been widely used in
other packages, has been tested over a period of time, and inherits the
properties of an array
in R.
Let’s say you have a T1-weighted NIfTI on your machine. If you do not, we can download one. We are downloading this to a temporary file since we don’t need it after the session is over:
= tempfile(fileext = ".nii.gz")
t1_file = paste0("https://johnmuschelli.com/",
url "open_ms_data/", "cross_sectional/",
"raw/patient01/T1W.nii.gz")
download.file(url, destfile = t1_file)
t1_file#> [1] "/var/folders/1s/wrtqcpxn685_zk570bnx9_rr0000gr/T//Rtmp61iZtG/file509017a5b571.nii.gz"
Here we will use the readnii
function to read in the
image to an object called img
:
library(neurobase)
= readnii(t1_file)
img
img#> NIfTI-1 format
#> Type : nifti
#> Data Type : 4 (INT16)
#> Bits per Pixel : 16
#> Slice Code : 0 (Unknown)
#> Intent Code : 0 (None)
#> Qform Code : 2 (Aligned_Anat)
#> Sform Code : 1 (Scanner_Anat)
#> Dimension : 408 x 512 x 152
#> Pixel Dimension : 0.43 x 0.43 x 0.82
#> Voxel Units : mm
#> Time Units : Unknown
We see the output is a nifti
object. We can think of
this as an array with additional information (called a header). We can
do simple operations on the image, such as sum
:
sum(img)
#> [1] 4073996312
sum(img > 1000)
#> [1] 278650
Let’s say we want to set all values greater than 1000 to 1000 and
then write the image out. We will use the writenii
function. We will copy img
to img2
because we
want to keep img
as is. Again we will write the image to a
temporary file because we don’t need this after the session:
= img
img2 > 1000] = 1000
img2[ img2 = tempfile(fileext = ".nii.gz")
outfile writenii(img2, outfile)
file.exists(outfile)
#> [1] TRUE
nifti
objectsAlthough the nifti
object is not a standard R object,
you can perform standard operations on these objects, such as
addition/subtraction and logic. This is referred to “overloaded”
operators.
For example, if we want to create a nifti
object with
binary values, where the values are TRUE
if the values in
img
are greater than 0, we can simply write:
= img > 0
above_zero class(above_zero)
#> [1] "nifti"
#> attr(,"package")
#> [1] "oro.nifti"
img_data(above_zero)[1]
#> [1] FALSE
We will refer to binary images/nifti
objects as
“masks”.
We can combine multiple operators, such as creating a binary mask for value greater than 0 and less than 2.
class(img > 0 & img < 2)
#> [1] "nifti"
#> attr(,"package")
#> [1] "oro.nifti"
nifti
objectsWe can also show the
class(img * 2)
#> [1] "nifti"
#> attr(,"package")
#> [1] "oro.nifti"
class(img + (img / 4))
#> [1] "nifti"
#> attr(,"package")
#> [1] "oro.nifti"
class(img * img)
#> [1] "nifti"
#> attr(,"package")
#> [1] "oro.nifti"
class(img^2)
#> [1] "nifti"
#> attr(,"package")
#> [1] "oro.nifti"
nifti
objectsThe neurobase::ortho2
function expands the
oro.nifti::orthographic
function for displaying
nifti
objects in 3 different planes:
::ortho2(img) neurobase
We see that in ortho2
there are annotations of the
orientation of the image. Again, if the image was not reoriented, then
these many not be correct. You can turn these off with the
add.orient
argument:
::ortho2(img, add.orient = FALSE) neurobase
We may want to view a single slice of an image. The
oro.nifti::slice
function can be used here.
::slice(img, z = 45) oro.nifti
We can also get a view of multiple slices:
::slice(img, z = c(45, 50)) oro.nifti
We can specify z
the same way but change the
plane
to be different to get a different slice of the
brain:
::slice(img, z = 52, plane = "sagittal") oro.nifti
We can similarly do the same for “coronal” slices.
We can also overlay one slice of an image upon another using the
oro.nifti::overlay
function. Here we must specify
plot.type
for only one slice.
overlay(img, y = img > quantile(img, 0.9), z = 45, plot.type = "single",
NA.y = TRUE)