<jupyter_start><jupyter_text>Introduction to Diffusion MRI data Diffusion Weighted Imaging (DWI)Diffusion imaging probes the random, microscopic motion of water protons by employing MRI sequences which are sensitive to the geometry and environmental organization surrounding the water protons. This is a popular technique for studying the white matter of the brain. The diffusion within biological structures, such as the brain, are often restricted due to barriers (eg. cell membranes), resulting in a preferred direction of diffusion (anisotropy). A typical diffusion MRI scan will acquire multiple volumes that are sensitive to a particular diffusion direction and result in diffusion-weighted images (DWI). Diffusion that exhibits directionality in the same direction result in an attenuated signal. With further processing (to be discussed later in the lesson), the acquired images can provide measurements which are related to the microscopic changes and estimate white matter trajectories. Images with no diffusion weighting are also acquired as part of the acquisition protocol.![fiber_configurations](DiffusionDirections.png) \Diffusion along X, Y, and Z directions  b-values & b-vectorsIn addition to the acquired diffusion images, two files are collected as part of the diffusion dataset. These files correspond to the gradient amplitude (b-values) and directions (b-vectors) of the diffusion measurement and are named with the extensions `.bval` and `.bvec` respectively. The b-value is the diffusion-sensitizing factor, and reflects the timing & strength of the gradients used to acquire the diffusion-weighted images. The b-vector corresponds to the direction of the diffusion sensitivity. Together these two files define the diffusion MRI measurement as a set of gradient directions and corresponding amplitudes.  DatasetFor the rest of this tutorial, we will make use of a subset of publicly available dataset, ds000030, from [openneuro.org](https://openneuro.org/datasets/ds000030) The dataset is structured according to the Brain Imaging Data Structure ([BIDS](https://bids-specification.readthedocs.io/en/etable/)).  Below is a tree diagram showing the folder structure of a single MR session within ds000030. This was obtained by using the bash command `tree`.  `!tree ../data/ds000030````ds000030├── CHANGES├── code├── dataset_description.json├── README└── sub-10788/    ├── anat    │   ├── sub-10788_T1w.json    │   └── sub-10788_T1w.nii.gz    └── dwi        ├── sub-10788_dwi.bval        │── sub-10788_dwi.bvec        │── sub-10788_dwi.json        └── sub-10788_dwi.nii.gz```<jupyter_code>!aws s3 sync --no-sign-request \
  s3://openneuro/ds000030/ds000030_R1.0.5/uncompressed/sub-10788 \
  ../../data/ds000030/sub-10788 \
  --exclude '*' \
  --include '*T1w*' \
  --include '*dwi*'<jupyter_output><empty_output><jupyter_text>Querying a BIDS Dataset[`pybids`](https://bids-standard.github.io/pybids/) is a Python API for querying, summarizing and manipulating the BIDS folder structure. We will make use of `pybids` to query the necessary files. Lets first pull the metadata from its associated JSON file using the `get_metadata()` function for the first run.<jupyter_code>from bids.layout import BIDSLayout

layout = BIDSLayout("../../data/ds000030", validate=False)
dwi = layout.get(subject='10788', suffix='dwi', extension='nii.gz', return_type='file')[0]
layout.get_metadata(dwi)<jupyter_output><empty_output><jupyter_text>[`dipy`](http://dipy.org)For this lesson, we will use the `Dipy` (Diffusion Imaging in Python) package for processing and analysing diffusion MRI. Why `dipy`? - Fully free and open source- Implemented in Python. Easy to understand, and easy to use.- Implementations of many state-of-the art algorithms- High performance. Many algorithms implemented in [`cython`](http://cython.org/) Installing `dipy`The easiest way to install `Dipy` is to use `pip`! Additionally, `Dipy` makes use of the FURY library for visualization. We will also install this using `pip`!We can install it by entering the following in a terminal `pip install dipy`. We will do so using Jupyter Magic in the following cell!  Defining a measurement: `GradientTable``Dipy` has a built-in function that allows us to read in `bval` and `bvec` files named `read_bvals_bvecs` under the `dipy.io.gradients` module. Let's first grab the path to our gradient directions and amplitude files and load them into memory.<jupyter_code>dwi = layout.get(subject='10788', suffix='dwi', extension='.nii.gz', return_type='file')[0]
bvec = layout.get(subject='10788', suffix='dwi', extension='bvec', return_type='file')[0]
bval = layout.get(subject='10788', suffix='dwi', extension='bval', return_type='file')[0]
import numpy as np
import nibabel as nib

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
%matplotlib notebook
data = nib.load(dwi).get_fdata()
data.shape
x_slice = data[58, :, :, 0]
y_slice = data[:, 58, :, 0]
z_slice = data[:, :, 30, 0]

slices = [x_slice, y_slice, z_slice]

fig, axes = plt.subplots(1, len(slices))
for i, slice in enumerate(slices):
    axes[i].imshow(slice.T, cmap="gray", origin="lower")
x_slice = data[58, :, :, 2]
y_slice = data[:, 58, :, 2]
z_slice = data[:, :, 30, 2]

slices = [x_slice, y_slice, z_slice]

fig, axes = plt.subplots(1, len(slices))
for i, slice in enumerate(slices):
    axes[i].imshow(slice.T, cmap="gray", origin="lower")
bvec_txt = np.genfromtxt(bvec)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(bvec_txt[0], bvec_txt[1], bvec_txt[2])

plt.show
from dipy.io.gradients import read_bvals_bvecs
from dipy.core.gradients import gradient_table

gt_bvals, gt_bvecs = read_bvals_bvecs(bval, bvec)<jupyter_output><empty_output><jupyter_text>There is a also simple `GradientTable` object implemented in the `dipy.core.gradients` module. The input to the `GradientTable` should be our the values for our gradient directions and amplitudes we just read.<jupyter_code>gtab = gradient_table(gt_bvals, gt_bvecs)<jupyter_output><empty_output><jupyter_text>We will need this gradient table later on to process our data and generate diffusion tensor images (DTI)! There is also a built in function for gradient tables, `b0s_mask` that can be used to separate diffusion weighted measurements from non-diffusion weighted measurements (b=0s/mm^2). Try to extract the vector corresponding to diffusion weighted measurements in the following cell!<jupyter_code>gtab.bvecs[~gtab.b0s_mask]<jupyter_output><empty_output><jupyter_text>It is also important to know where our diffusion weighting free measurements are as we need them for registration in our preprocessing, (our next notebook). The gtab.b0s_mask shows that this is our first volume of our dataset.<jupyter_code>gtab.b0s_mask
b0 = data[:, :, :, gtab.b0s_mask]
b0.shape
b0 = np.squeeze(b0)
x_slice = b0[58, :, :]
y_slice = b0[:, 58, :]
z_slice = b0[:, :, 30]

slices = [x_slice, y_slice, z_slice]

fig, axes = plt.subplots(1, len(slices))
for i, slice in enumerate(slices):
    axes[i].imshow(slice.T, cmap="gray", origin="lower")<jupyter_output><empty_output>
StarcoderdataJupyterStructuredCleanDedup