--- title: "Simple Image Input/Output" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Simple Image Input/Output} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(neurobase) ``` # The nifti object 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. # Downloading an Image 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: ```{r} t1_file = tempfile(fileext = ".nii.gz") url = paste0("https://johnmuschelli.com/", "open_ms_data/", "cross_sectional/", "raw/patient01/T1W.nii.gz") download.file(url, destfile = t1_file) t1_file ``` # Reading in an image Here we will use the `readnii` function to read in the image to an object called `img`: ```{r} library(neurobase) img = readnii(t1_file) img ``` 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`: ```{r} sum(img) sum(img > 1000) ``` # Writing Images 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: ```{r} img2 = img img2[ img2 > 1000] = 1000 outfile = tempfile(fileext = ".nii.gz") writenii(img2, outfile) file.exists(outfile) ``` # Operations of `nifti` objects Although 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. ## Logical 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: ```{r logical} above_zero = img > 0 class(above_zero) img_data(above_zero)[1] ``` 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. ```{r multi_log} class(img > 0 & img < 2) ``` ## Arithmetic on `nifti` objects We can also show the ```{r} class(img * 2) class(img + (img / 4)) class(img * img) class(img^2) ``` # Visualization of `nifti` objects ## Orthographic view The `neurobase::ortho2` function expands the `oro.nifti::orthographic` function for displaying `nifti` objects in 3 different planes: ```{r ortho2} neurobase::ortho2(img) ``` 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: ```{r ortho2_noorient} neurobase::ortho2(img, add.orient = FALSE) ``` ## Single slice view We may want to view a single slice of an image. The `oro.nifti::slice` function can be used here. ```{r all_slices} oro.nifti::slice(img, z = 45) ``` We can also get a view of multiple slices: ```{r two_slice} oro.nifti::slice(img, z = c(45, 50)) ``` ### Different Planes We can specify `z` the same way but change the `plane` to be different to get a different slice of the brain: ```{r one_slice_sag} oro.nifti::slice(img, z = 52, plane = "sagittal") ``` We can similarly do the same for "coronal" slices. ## Overlaying 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. ```{r one_slice_overlay} overlay(img, y = img > quantile(img, 0.9), z = 45, plot.type = "single", NA.y = TRUE) ```