Commit d45eedcc authored by William Clarke's avatar William Clarke
Browse files

Update example usage notebooks.

parent 250bb289
No preview for this file type
......@@ -46,20 +46,9 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[]"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
"#%%capture\n",
"%sx mkdir -p MRSI\n",
......@@ -79,20 +68,9 @@
},
{
"cell_type": "code",
"execution_count": 13,
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[]"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
"%sx fsl_mrsi --data example_data/example_mrsi/mrsi.nii.gz \\\n",
" --basis example_data/example_mrsi/3T_slaser_32vespa_1250.BASIS \\\n",
......@@ -123,26 +101,9 @@
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['total 272',\n",
" 'drwxr-xr-x 6 saad staff 192 15 Jun 21:45 concs',\n",
" 'drwxr-xr-x 8 saad staff 256 15 Jun 21:45 fit',\n",
" '-rw-r--r-- 1 saad staff 134462 15 Jun 21:43 fit_avg.png',\n",
" '-rw-r--r-- 1 saad staff 1388 15 Jun 21:43 options.txt',\n",
" 'drwxr-xr-x 50 saad staff 1600 15 Jun 21:45 qc',\n",
" 'drwxr-xr-x 31 saad staff 992 15 Jun 21:45 uncertainties']"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
"%sx ls -l MRSI/example_mrsi_fit"
]
......@@ -163,7 +124,9 @@
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
"source": [
"%sx fsleyes example_data/example_mrsi/T1.anat/T1.nii.gz example_data/example_mrsi/mrsi.nii.gz MRSI/example_mrsi_fit/fit/fit.nii.gz MRSI/example_mrsi_fit/fit/baseline.nii.gz MRSI/example_mrsi_fit/concs/internal/NAA+NAAG.nii.gz"
]
}
],
"metadata": {
......@@ -182,7 +145,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
"version": "3.7.7"
}
},
"nbformat": 4,
......
%% Cell type:markdown id: tags:
# Example of MRSI fitting on the command line
This notebook demos the process of fitting an MRSI scan using the command line scripts included in FSL-MRS.
### Contents:
- [1. Reconstruction, Processing and Data Conversion](#1.-Reconstruction,-processing-and-data-conversion)
- [2. Segmentation](#2.-Tissue-segmentation)
- [3. Fitting](#3.-Fitting)
- [4. Visualisation of fit](#4.-Visualisation-of-fit)
Will Clarke
June 2020
University of Oxford
%% Cell type:markdown id: tags:
## 1. Reconstruction, processing and data conversion
MRSI reconstruction (from k-space data) can be highly specialised depending on the sequence. For example reconstruction of non-cartesian trajectories (e.g. spirals or concentric-rings) requires regridding or use of the NUFFT. Due to the specialised nature of MRSI reconstruction FSL-MRS does not contain tools for this step.
Simmilarly post-processing of MRSI data is commonly done as part of the reconstruction process. Though many of the processing tools in FSL-MRS can be run on MRSI data they have not been created with MRSI in mind.
This example therefore assumes that you are able to provide reconstructed and processed data ready for fitting. Data can be converted to NIfTI from the Siemens DICOM format using spec2nii. The authors of FSL-MRS and spec2nii are happy to add supported formats if example data and interpretation is provided.
%% Cell type:markdown id: tags:
## 2. Tissue segmentation
Tissue segmentation is required to have meaningful scaling of water referenced metabolite concentrations. mrsi_segment will produce three files, corresponding to the GM, WM and CSF FAST tissue segmentations registered to the MRSI volume.
Run tissue segmentation on the packaged T1 data and mask using the MRSI data file. Here we provide a (partial) .anat file produced by [fsl_anat](https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/fsl_anat) to speed up execution.
This step requires an installation of FSL compatible with fslpy.
%% Cell type:code id: tags:
``` python
#%%capture
%sx mkdir -p MRSI
%sx mrsi_segment -o MRSI -a example_data/example_mrsi/T1.anat example_data/example_mrsi/mrsi.nii.gz
```
%%%% Output: execute_result
[]
%% Cell type:markdown id: tags:
## 3. Fitting
The below is a call to the main MRSI wrapper script. Not the use of the :code:`--add_MM` flag as this metabolite basis does not contain a macromolecule basis. Also note that the mrsi dataset provided is accompagnied by a JSON sidecar file which contains some useful information such as the echo time, the central frequency, and the dwell time.
The script will by default run in parallel on the available CPU cores. Depending on hardware this should take a few minutes.
%% Cell type:code id: tags:
``` python
%sx fsl_mrsi --data example_data/example_mrsi/mrsi.nii.gz \
--basis example_data/example_mrsi/3T_slaser_32vespa_1250.BASIS \
--output MRSI/example_mrsi_fit \
--mask example_data/example_mrsi/mask.nii.gz \
--h2o example_data/example_mrsi/wref.nii.gz \
--tissue_frac MRSI/mrsi_seg_wm.nii.gz MRSI/mrsi_seg_gm.nii.gz MRSI/mrsi_seg_csf.nii.gz \
--add_MM \
--baseline_order 2 \
--combine PCho GPC --combine Cr PCr --combine NAA NAAG --combine Glu Gln --combine Glc Tau \
--ignore Gly HG \
--overwrite
```
%%%% Output: execute_result
[]
%% Cell type:markdown id: tags:
## 4. Visualisation of fit
Now take a look at the outputs. A PNG of the fit to the average of all voxels is provided for a quick sanity check. The folders contain the following:
- concs : concentration for each metabolite or combined metabolites (subfolders contain different types of referencing)
- fit : the model prediction FID, the residual FID, and the baseline (also in the time domain).
- qc : QC parameters split per metabolite
- uncertainties : the std of the fit per metabolite
%% Cell type:code id: tags:
``` python
%sx ls -l MRSI/example_mrsi_fit
```
%%%% Output: execute_result
['total 272',
'drwxr-xr-x 6 saad staff 192 15 Jun 21:45 concs',
'drwxr-xr-x 8 saad staff 256 15 Jun 21:45 fit',
'-rw-r--r-- 1 saad staff 134462 15 Jun 21:43 fit_avg.png',
'-rw-r--r-- 1 saad staff 1388 15 Jun 21:43 options.txt',
'drwxr-xr-x 50 saad staff 1600 15 Jun 21:45 qc',
'drwxr-xr-x 31 saad staff 992 15 Jun 21:45 uncertainties']
%% Cell type:markdown id: tags:
Now run the command below in a terminal in order to load the data in FSLeyes. Follow the instructions [here](https://users.fmrib.ox.ac.uk/~saad/fsl_mrs/html/visualisation.html#fsleyes) to set it up in such a way that you can explore each voxel's individual fit.
```
fsleyes example_data/example_mrsi/T1.anat/T1.nii.gz example_data/example_mrsi/mrsi.nii.gz MRSI/example_mrsi_fit/fit/fit.nii.gz MRSI/example_mrsi_fit/fit/baseline.nii.gz MRSI/example_mrsi_fit/concs/internal/NAA+NAAG.nii.gz
```
%% Cell type:code id: tags:
``` python
%sx fsleyes example_data/example_mrsi/T1.anat/T1.nii.gz example_data/example_mrsi/mrsi.nii.gz MRSI/example_mrsi_fit/fit/fit.nii.gz MRSI/example_mrsi_fit/fit/baseline.nii.gz MRSI/example_mrsi_fit/concs/internal/NAA+NAAG.nii.gz
```
......
......@@ -32,11 +32,9 @@
"source": [
"## 1. File conversion using spec2nii\n",
"\n",
"Run spec2nii twix -v to establish the file contents, then using this information run spec2nii twix -e with the appropriate flags to extract the required scans.\n",
"Run spec2nii twix -v to establish the file contents, then using this information run spec2nii twix -e with the appropriate flags to extract the required scans. The -q flag suppresses text output.\n",
"\n",
"The -j option causes a JSON side-car file to be generated. The -q flag suppresses text output.\n",
"\n",
"This dataset uses a modified versions of the cmrr spectro package sequences on a siemens scanner. It has three sets of water reference scans. The first is taged as a phase correction, iscollected at the start of the main suppressed water scan and will be used for eddy current correction.\n",
"This dataset uses a modified versions of the CMRR spectro package sequences on a Siemens scanner. It has three sets of water reference scans. The first is tagged as a phase correction, ans is collected at the start of the main suppressed water scan and will be used for eddy current correction.\n",
"\n",
"The second is collected in a separate scan with only the RF portion of the water suppression disabled. This is used for coil combination (and could be used for eddy current correction). The third is collected with the OVS and all aspects of the water suppression disabled. It therefore experiences eddy currents unlike all the other scans. It will be used for final concentration scaling."
]
......@@ -60,7 +58,7 @@
"The first is tagged as \"image\" and contains 64 repetitions (sets) of 4096 point FIDs collected on 32 channels. \n",
"The second has a single FID on each channel.\n",
"\n",
"We now call spec2nii again specifying the group we want to extract each time. spec2nii will generate a NIfTI file for each repetition (set) with a size of 1x1x1x4096x32. \n",
"We now call spec2nii again specifying the group we want to extract each time. Each call to spec2nii will generate a NIfTI MRS file with a size of 1x1x1x4096x32xNdyn, where Ndyn is the number of dynamics (repeats).\n",
" \n",
"We repeat this for the water reference scans, extracting just the image data."
]
......@@ -72,11 +70,11 @@
"outputs": [],
"source": [
"%%bash\n",
"spec2nii twix -e image -f steam_metab_raw -o data -j -q example_data/meas_MID310_STEAM_metab_FID115673.dat\n",
"spec2nii twix -e phasecor -f steam_ecc_raw -o data -j -q example_data/meas_MID310_STEAM_metab_FID115673.dat\n",
"spec2nii twix -e image -f steam_metab_raw -o data -q example_data/meas_MID310_STEAM_metab_FID115673.dat\n",
"spec2nii twix -e phasecor -f steam_ecc_raw -o data -q example_data/meas_MID310_STEAM_metab_FID115673.dat\n",
"\n",
"spec2nii twix -e image -f steam_wref_comb_raw -o data -j -q example_data/meas_MID311_STEAM_wref1_FID115674.dat\n",
"spec2nii twix -e image -f steam_wref_quant_raw -o data -j -q example_data/meas_MID312_STEAM_wref3_FID115675.dat"
"spec2nii twix -e image -f steam_wref_comb_raw -o data -q example_data/meas_MID311_STEAM_wref1_FID115674.dat\n",
"spec2nii twix -e image -f steam_wref_quant_raw -o data -q example_data/meas_MID312_STEAM_wref3_FID115675.dat"
]
},
{
......@@ -96,11 +94,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"After conversion we have 64 averages from the suppressed water scan. The \"Set\" descriptor at the end of the file name arises from the indexing loop used at acquisition time to store the data. This is likely to vary from sequence to sequence, and is the choice of the pulse sequence programmer. Multiple looping indicies might be used for more complex data acquisition strategies. \n",
"After conversion we have four files. steam_metab_raw is the the suppressed water data. \n",
" \n",
"We also have one ecc scan, and two \"Reps\" (another looping index) of each of the water reference scans. In this case both Set and Rep are used to indicate transients that should be averaged toghether.\n",
"\n",
"Notice that each NIfTI file is paired witht a JSON sidecar file which contains useful information for further processing."
"We also have one ecc scan, and two water reference scans. The former contains a single dynamic, whilst the latter two contain two dynamics. All have data from 32 uncombined coils."
]
},
{
......@@ -117,7 +113,7 @@
"1. Take averages of water references used for combination across files\n",
"2. Coil combine the metab data, the ecc data and the quantification data using the \"comb\" data as the reference.\n",
"3. Phase and frequency align the data where there are multiple transients.\n",
"4. Combine data across those transients (one in each file) by taking the mean.\n",
"4. Combine data across those transients by taking the mean.\n",
"5. Run eddy current correction using the appropriate reference.\n",
"6. In this data an additional FID point is collected before the echo centre. Remove this.\n",
"7. Run HLSVD on the data to remove the residual water in the water suppressed data.\n",
......@@ -136,21 +132,21 @@
"if not os.path.isdir('fsl_mrs_proc'):\n",
" os.mkdir('fsl_mrs_proc')\n",
"\n",
"#1. Combine comb water data across files\n",
"%sx fsl_mrs_proc average --file data/steam_wref_comb_raw*.nii.gz --avgfiles --output fsl_mrs_proc --filename steam_wref_comb\n",
"#1. Combine water reference data for combination across dynamics\n",
"%sx fsl_mrs_proc average --file data/steam_wref_comb_raw.nii.gz --dim DIM_DYN --output fsl_mrs_proc --filename steam_wref_comb\n",
"\n",
"#2. Run coil combination on the three sets of data\n",
"%sx fsl_mrs_proc coilcombine --file data/steam_metab_raw*.nii.gz --reference fsl_mrs_proc/steam_wref_comb.nii.gz --output fsl_mrs_proc -r \n",
"%sx fsl_mrs_proc coilcombine --file data/steam_wref_quant_raw*.nii.gz --reference fsl_mrs_proc/steam_wref_comb.nii.gz --output fsl_mrs_proc \n",
"%sx fsl_mrs_proc coilcombine --file data/steam_metab_raw.nii.gz --reference fsl_mrs_proc/steam_wref_comb.nii.gz --output fsl_mrs_proc -r \n",
"%sx fsl_mrs_proc coilcombine --file data/steam_wref_quant_raw.nii.gz --reference fsl_mrs_proc/steam_wref_comb.nii.gz --output fsl_mrs_proc \n",
"%sx fsl_mrs_proc coilcombine --file data/steam_ecc_raw.nii.gz --reference fsl_mrs_proc/steam_wref_comb.nii.gz --output fsl_mrs_proc \n",
"\n",
"#3. Align averages of water ref and metab data\n",
"%sx fsl_mrs_proc align --file fsl_mrs_proc/steam_metab_raw*.nii.gz --ppm 1.8 3.5 --output fsl_mrs_proc -r --filename steam_metab_align --apod 50 \n",
"%sx fsl_mrs_proc align --file fsl_mrs_proc/steam_wref_quant_raw*.nii.gz --ppm 4 6 --output fsl_mrs_proc --filename steam_water_align \n",
"%sx fsl_mrs_proc align --file fsl_mrs_proc/steam_metab_raw.nii.gz --ppm 1.8 3.5 --output fsl_mrs_proc -r --filename steam_metab_align --apod 50 \n",
"%sx fsl_mrs_proc align --file fsl_mrs_proc/steam_wref_quant_raw.nii.gz --ppm 4 6 --output fsl_mrs_proc --filename steam_water_align \n",
"\n",
"#3. Combine data across averages\n",
"%sx fsl_mrs_proc average --file fsl_mrs_proc/steam_metab_align*.nii.gz --avgfiles --output fsl_mrs_proc -r --filename steam_metab_comb \n",
"%sx fsl_mrs_proc average --file fsl_mrs_proc/steam_water_align*.nii.gz --avgfiles --output fsl_mrs_proc --filename steam_wquant_comb \n",
"%sx fsl_mrs_proc average --file fsl_mrs_proc/steam_metab_align.nii.gz --dim DIM_DYN --output fsl_mrs_proc -r --filename steam_metab_comb \n",
"%sx fsl_mrs_proc average --file fsl_mrs_proc/steam_water_align.nii.gz --dim DIM_DYN --output fsl_mrs_proc --filename steam_wquant_comb \n",
"\n",
"#5. Run the eddy current correction on the data\n",
"%sx fsl_mrs_proc ecc --file fsl_mrs_proc/steam_metab_comb.nii.gz --reference fsl_mrs_proc/steam_ecc_raw.nii.gz --output fsl_mrs_proc -r --filename steam_metab_comb_ecc \n",
......@@ -195,15 +191,13 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"metadata": {},
"outputs": [],
"source": [
"%sx fsl_mrs_preproc --output fsl_mrs_preproc --data data/steam_metab_raw*.nii.gz --reference data/steam_wref_comb_raw*.nii.gz --quant data/steam_wref_quant_raw*.nii.gz --ecc data/steam_ecc_raw.nii.gz --hlsvd --leftshift 1 --t1 example_data/T1_biascorr.nii.gz --overwrite --report \n",
"%sx fsl_mrs_preproc --output fsl_mrs_preproc --data data/steam_metab_raw.nii.gz --reference data/steam_wref_comb_raw.nii.gz --quant data/steam_wref_quant_raw.nii.gz --ecc data/steam_ecc_raw.nii.gz --hlsvd --leftshift 1 --t1 example_data/T1.anat/T1_biascorr.nii.gz --overwrite --report \n",
"\n",
"# You can also run this script without independent quant and ecc data (just 1 water reference)\n",
"%sx fsl_mrs_preproc --output fsl_mrs_preproc_simple --data data/steam_metab_raw*.nii.gz --reference data/steam_wref_comb_raw*.nii.gz --hlsvd --leftshift 1 --t1 example_data/T1_biascorr.nii.gz --overwrite --report "
"%sx fsl_mrs_preproc --output fsl_mrs_preproc_simple --data data/steam_metab_raw.nii.gz --reference data/steam_wref_comb_raw.nii.gz --hlsvd --leftshift 1 --t1 example_data/T1.anat/T1_biascorr.nii.gz --overwrite --report "
]
},
{
......@@ -213,7 +207,7 @@
"### 3. Run tissue segmentation\n",
"Run tissue segmentation on the packaged T1 data and mask using the SVS voxel. Here we provide a (partial) .anat file produced by [fsl_anat](https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/fsl_anat) to speed up execution.\n",
"\n",
"This step requires an installation of FSL compatible with fslpy. If you don't want to run this step the fitting step will run using a pre-packaged tissue segmentation file."
"This step requires an installation of FSL compatible with fslpy. If you don't want to run this step the fitting step can be run using a pre-packaged tissue segmentation file (example_data/segmentation.json)."
]
},
{
......@@ -240,8 +234,7 @@
"outputs": [],
"source": [
"# Quick fit \n",
"%sx fsl_mrs --data fsl_mrs_preproc/metab.nii.gz --basis example_data/steam_11ms --output fit_short --metab_groups Mac --overwrite --report --t1 example_data/T1.anat/T1_biascorr.nii.gz --h2o fsl_mrs_preproc/wref.nii.gz --tissue_frac segmentation.json\n",
"\n"
"%sx fsl_mrs --data fsl_mrs_preproc/metab.nii.gz --basis example_data/steam_11ms --output fit_short --metab_groups Mac --overwrite --report --t1 example_data/T1.anat/T1_biascorr.nii.gz --h2o fsl_mrs_preproc/wref.nii.gz --tissue_frac segmentation.json\n"
]
},
{
......@@ -309,5 +302,5 @@
}
},
"nbformat": 4,
"nbformat_minor": 2
"nbformat_minor": 4
}
%% Cell type:markdown id: tags:
# Example of SVS processing on the command line
%% Cell type:markdown id: tags:
This notebook demos the process of fitting a single voxel scan using the command line scripts included in FSL MRS.
### Contents:
- [1. File conversion using spec2nii](#1.-File-conversion-using-spec2nii)
- [2. Preprocessing in two ways](#2.-Preprocessing-of-the-data)
- [2.1. Using individual fsl_mrs_proc commands](#2.1-Pre-processing-using-fsl_mrs_proc)
- [2.2. In one step using the script fsl_mrs_preproc](#2.2-Pre-processing-using-fsl_mrs_preproc)
- [3. Tissue segmentation](#3.-Run-tissue-segmentation)
- [4. Fitting of the resultant spectrum](#4.-Fit-the-data)
- [5. Display the fitting reports](#5.-Display-the-result)
Will Clarke
June 2020
University of Oxford
%% Cell type:markdown id: tags:
## 1. File conversion using spec2nii
Run spec2nii twix -v to establish the file contents, then using this information run spec2nii twix -e with the appropriate flags to extract the required scans.
Run spec2nii twix -v to establish the file contents, then using this information run spec2nii twix -e with the appropriate flags to extract the required scans. The -q flag suppresses text output.
The -j option causes a JSON side-car file to be generated. The -q flag suppresses text output.
This dataset uses a modified versions of the cmrr spectro package sequences on a siemens scanner. It has three sets of water reference scans. The first is taged as a phase correction, iscollected at the start of the main suppressed water scan and will be used for eddy current correction.
This dataset uses a modified versions of the CMRR spectro package sequences on a Siemens scanner. It has three sets of water reference scans. The first is tagged as a phase correction, ans is collected at the start of the main suppressed water scan and will be used for eddy current correction.
The second is collected in a separate scan with only the RF portion of the water suppression disabled. This is used for coil combination (and could be used for eddy current correction). The third is collected with the OVS and all aspects of the water suppression disabled. It therefore experiences eddy currents unlike all the other scans. It will be used for final concentration scaling.
%% Cell type:code id: tags:
``` python
%%bash
spec2nii twix -v -q example_data/meas_MID310_STEAM_metab_FID115673.dat
```
%% Cell type:markdown id: tags:
From the final lines of the output of the first cell we can see that this "twix" file contains two groups of data.
The first is tagged as "image" and contains 64 repetitions (sets) of 4096 point FIDs collected on 32 channels.
The second has a single FID on each channel.
We now call spec2nii again specifying the group we want to extract each time. spec2nii will generate a NIfTI file for each repetition (set) with a size of 1x1x1x4096x32.
We now call spec2nii again specifying the group we want to extract each time. Each call to spec2nii will generate a NIfTI MRS file with a size of 1x1x1x4096x32xNdyn, where Ndyn is the number of dynamics (repeats).
We repeat this for the water reference scans, extracting just the image data.
%% Cell type:code id: tags:
``` python
%%bash
spec2nii twix -e image -f steam_metab_raw -o data -j -q example_data/meas_MID310_STEAM_metab_FID115673.dat
spec2nii twix -e phasecor -f steam_ecc_raw -o data -j -q example_data/meas_MID310_STEAM_metab_FID115673.dat
spec2nii twix -e image -f steam_metab_raw -o data -q example_data/meas_MID310_STEAM_metab_FID115673.dat
spec2nii twix -e phasecor -f steam_ecc_raw -o data -q example_data/meas_MID310_STEAM_metab_FID115673.dat
spec2nii twix -e image -f steam_wref_comb_raw -o data -j -q example_data/meas_MID311_STEAM_wref1_FID115674.dat
spec2nii twix -e image -f steam_wref_quant_raw -o data -j -q example_data/meas_MID312_STEAM_wref3_FID115675.dat
spec2nii twix -e image -f steam_wref_comb_raw -o data -q example_data/meas_MID311_STEAM_wref1_FID115674.dat
spec2nii twix -e image -f steam_wref_quant_raw -o data -q example_data/meas_MID312_STEAM_wref3_FID115675.dat
```
%% Cell type:code id: tags:
``` python
%%bash
# Check the content of the output folder
ls data
```
%% Cell type:markdown id: tags:
After conversion we have 64 averages from the suppressed water scan. The "Set" descriptor at the end of the file name arises from the indexing loop used at acquisition time to store the data. This is likely to vary from sequence to sequence, and is the choice of the pulse sequence programmer. Multiple looping indicies might be used for more complex data acquisition strategies.
We also have one ecc scan, and two "Reps" (another looping index) of each of the water reference scans. In this case both Set and Rep are used to indicate transients that should be averaged toghether.
After conversion we have four files. steam_metab_raw is the the suppressed water data.
Notice that each NIfTI file is paired witht a JSON sidecar file which contains useful information for further processing.
We also have one ecc scan, and two water reference scans. The former contains a single dynamic, whilst the latter two contain two dynamics. All have data from 32 uncombined coils.
%% Cell type:markdown id: tags:
## 2. Preprocessing of the data
### 2.1 Pre-processing using fsl_mrs_proc
In this section we will preprocess the data using individual subcommands of the fsl_mrs_proc script to preprocess step-by-step. This example could be used as a template to construct your own preprocessing script in either python or another batch processing script (e.g. bash).
#### Description of steps
1. Take averages of water references used for combination across files
2. Coil combine the metab data, the ecc data and the quantification data using the "comb" data as the reference.
3. Phase and frequency align the data where there are multiple transients.
4. Combine data across those transients (one in each file) by taking the mean.
4. Combine data across those transients by taking the mean.
5. Run eddy current correction using the appropriate reference.
6. In this data an additional FID point is collected before the echo centre. Remove this.
7. Run HLSVD on the data to remove the residual water in the water suppressed data.
6. Phase the data by a single peak as a crude zero-order phase correction.
Note that the "%sx" command is only required in this example notebook and are unecessary on the command line.
%% Cell type:code id: tags:
``` python
import os
if not os.path.isdir('fsl_mrs_proc'):
os.mkdir('fsl_mrs_proc')
#1. Combine comb water data across files
%sx fsl_mrs_proc average --file data/steam_wref_comb_raw*.nii.gz --avgfiles --output fsl_mrs_proc --filename steam_wref_comb
#1. Combine water reference data for combination across dynamics
%sx fsl_mrs_proc average --file data/steam_wref_comb_raw.nii.gz --dim DIM_DYN --output fsl_mrs_proc --filename steam_wref_comb
#2. Run coil combination on the three sets of data
%sx fsl_mrs_proc coilcombine --file data/steam_metab_raw*.nii.gz --reference fsl_mrs_proc/steam_wref_comb.nii.gz --output fsl_mrs_proc -r
%sx fsl_mrs_proc coilcombine --file data/steam_wref_quant_raw*.nii.gz --reference fsl_mrs_proc/steam_wref_comb.nii.gz --output fsl_mrs_proc
%sx fsl_mrs_proc coilcombine --file data/steam_metab_raw.nii.gz --reference fsl_mrs_proc/steam_wref_comb.nii.gz --output fsl_mrs_proc -r
%sx fsl_mrs_proc coilcombine --file data/steam_wref_quant_raw.nii.gz --reference fsl_mrs_proc/steam_wref_comb.nii.gz --output fsl_mrs_proc
%sx fsl_mrs_proc coilcombine --file data/steam_ecc_raw.nii.gz --reference fsl_mrs_proc/steam_wref_comb.nii.gz --output fsl_mrs_proc
#3. Align averages of water ref and metab data
%sx fsl_mrs_proc align --file fsl_mrs_proc/steam_metab_raw*.nii.gz --ppm 1.8 3.5 --output fsl_mrs_proc -r --filename steam_metab_align --apod 50
%sx fsl_mrs_proc align --file fsl_mrs_proc/steam_wref_quant_raw*.nii.gz --ppm 4 6 --output fsl_mrs_proc --filename steam_water_align
%sx fsl_mrs_proc align --file fsl_mrs_proc/steam_metab_raw.nii.gz --ppm 1.8 3.5 --output fsl_mrs_proc -r --filename steam_metab_align --apod 50
%sx fsl_mrs_proc align --file fsl_mrs_proc/steam_wref_quant_raw.nii.gz --ppm 4 6 --output fsl_mrs_proc --filename steam_water_align
#3. Combine data across averages
%sx fsl_mrs_proc average --file fsl_mrs_proc/steam_metab_align*.nii.gz --avgfiles --output fsl_mrs_proc -r --filename steam_metab_comb
%sx fsl_mrs_proc average --file fsl_mrs_proc/steam_water_align*.nii.gz --avgfiles --output fsl_mrs_proc --filename steam_wquant_comb
%sx fsl_mrs_proc average --file fsl_mrs_proc/steam_metab_align.nii.gz --dim DIM_DYN --output fsl_mrs_proc -r --filename steam_metab_comb
%sx fsl_mrs_proc average --file fsl_mrs_proc/steam_water_align.nii.gz --dim DIM_DYN --output fsl_mrs_proc --filename steam_wquant_comb
#5. Run the eddy current correction on the data
%sx fsl_mrs_proc ecc --file fsl_mrs_proc/steam_metab_comb.nii.gz --reference fsl_mrs_proc/steam_ecc_raw.nii.gz --output fsl_mrs_proc -r --filename steam_metab_comb_ecc
%sx fsl_mrs_proc ecc --file fsl_mrs_proc/steam_wquant_comb.nii.gz --reference fsl_mrs_proc/steam_wquant_comb.nii.gz --output fsl_mrs_proc --filename steam_wquant_comb_ecc
#6. Remove the first FID point
%sx fsl_mrs_proc truncate --file fsl_mrs_proc/steam_metab_comb_ecc.nii.gz --points -1 --pos first --output fsl_mrs_proc -r
%sx fsl_mrs_proc truncate --file fsl_mrs_proc/steam_wquant_comb_ecc.nii.gz --points -1 --pos first --output fsl_mrs_proc
#7. Run HLSVD on the data
%sx fsl_mrs_proc remove --file fsl_mrs_proc/steam_metab_comb_ecc.nii.gz --output fsl_mrs_proc -r --filename steam_metab_comb_ecc_hlsvd
#6. Phase the data
%sx fsl_mrs_proc phase --file fsl_mrs_proc/steam_metab_comb_ecc_hlsvd.nii.gz --output fsl_mrs_proc -r --filename metab
%sx fsl_mrs_proc phase --ppm 4.6 4.7 --file fsl_mrs_proc/steam_wquant_comb_ecc.nii.gz --output fsl_mrs_proc --filename water
```
%% Cell type:markdown id: tags:
Combine the reports generated by the individual preprocessing commands
%% Cell type:code id: tags:
``` python
%sx merge_mrs_reports -d CMD_line_test -o fsl_mrs_proc --delete fsl_mrs_proc/*.html
```
%% Cell type:markdown id: tags:
### 2.2 Pre-processing using fsl_mrs_preproc
In this section we will preprocess the data using a single preprocessing script which encapsulates all of the commands run above. Some of the commands are optional.
%% Cell type:code id: tags:
``` python
%sx fsl_mrs_preproc --output fsl_mrs_preproc --data data/steam_metab_raw*.nii.gz --reference data/steam_wref_comb_raw*.nii.gz --quant data/steam_wref_quant_raw*.nii.gz --ecc data/steam_ecc_raw.nii.gz --hlsvd --leftshift 1 --t1 example_data/T1_biascorr.nii.gz --overwrite --report
%sx fsl_mrs_preproc --output fsl_mrs_preproc --data data/steam_metab_raw.nii.gz --reference data/steam_wref_comb_raw.nii.gz --quant data/steam_wref_quant_raw.nii.gz --ecc data/steam_ecc_raw.nii.gz --hlsvd --leftshift 1 --t1 example_data/T1.anat/T1_biascorr.nii.gz --overwrite --report
# You can also run this script without independent quant and ecc data (just 1 water reference)
%sx fsl_mrs_preproc --output fsl_mrs_preproc_simple --data data/steam_metab_raw*.nii.gz --reference data/steam_wref_comb_raw*.nii.gz --hlsvd --leftshift 1 --t1 example_data/T1_biascorr.nii.gz --overwrite --report
%sx fsl_mrs_preproc --output fsl_mrs_preproc_simple --data data/steam_metab_raw.nii.gz --reference data/steam_wref_comb_raw.nii.gz --hlsvd --leftshift 1 --t1 example_data/T1.anat/T1_biascorr.nii.gz --overwrite --report
```
%% Cell type:markdown id: tags:
### 3. Run tissue segmentation
Run tissue segmentation on the packaged T1 data and mask using the SVS voxel. Here we provide a (partial) .anat file produced by [fsl_anat](https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/fsl_anat) to speed up execution.
This step requires an installation of FSL compatible with fslpy. If you don't want to run this step the fitting step will run using a pre-packaged tissue segmentation file.
This step requires an installation of FSL compatible with fslpy. If you don't want to run this step the fitting step can be run using a pre-packaged tissue segmentation file (example_data/segmentation.json).
%% Cell type:code id: tags:
``` python
%sx svs_segment -a example_data/T1.anat fsl_mrs_proc/metab.nii.gz
```
%% Cell type:markdown id: tags:
### 4. Fit the data
Run a quick fit using the Newton method (here using the processed data in `fsl_mrs_preproc`)
%% Cell type:code id: tags:
``` python
# Quick fit
%sx fsl_mrs --data fsl_mrs_preproc/metab.nii.gz --basis example_data/steam_11ms --output fit_short --metab_groups Mac --overwrite --report --t1 example_data/T1.anat/T1_biascorr.nii.gz --h2o fsl_mrs_preproc/wref.nii.gz --tissue_frac segmentation.json
```
%% Cell type:markdown id: tags:
Or run a full fit with the MCMC method
%% Cell type:code id: tags:
``` python
# Full fit
%sx fsl_mrs --data fsl_mrs_preproc/metab.nii.gz --basis example_data/steam_11ms --output fit_long --algo MH --metab_groups Mac --overwrite --report --t1 example_data/T1.anat/T1_biascorr.nii.gz --h2o fsl_mrs_preproc/wref.nii.gz --tissue_frac segmentation.json
```
%% Cell type:markdown id: tags:
### 5. Display the result
Display the html reports in new tabs
%% Cell type:code id: tags:
``` python
%%capture
import webbrowser
import os
current_path = os.getcwd()
# generate a URL
url = os.path.join('file:///'+current_path,'fsl_mrs_preproc/mergedReports.html')
webbrowser.open(url)
url = os.path.join('file:///'+current_path,'fit_short/report.html')
webbrowser.open(url)
url = os.path.join('file:///'+current_path,'fit_long/report.html')
webbrowser.open(url)
```
......
......@@ -552,6 +552,10 @@ class MRS(object):
from fsl_mrs.utils.plotting import plot_spectrum
plot_spectrum(self, ppmlim=ppmlim)
def plot_ref(self, ppmlim=(2.65, 6.65)):
from fsl_mrs.utils.plotting import plot_spectrum
plot_spectrum(self, FID=self.H2O, ppmlim=ppmlim)
def plot_fid(self, tlim=None):
from fsl_mrs.utils.plotting import plot_fid
plot_fid(self, tlim)
......
......@@ -291,7 +291,7 @@ def main():
else:
echotime = None
elif 'EchoTime' in FID.hdr_ext:
echotime = FID.hdr_ext['TE']
echotime = FID.hdr_ext['EchoTime']
else:
echotime = None
......
......@@ -246,7 +246,9 @@ def main():
ref_data = nifti_mrs_proc.ecc(ref_data, eccRef)
# Typically if a separate "quantification" water reference
# has been collected it will have most gradients removed
# (OVS and water suppression), therefore do not apply ecc.
# (OVS and water suppression), therefore use it as it's own reference.
if args.quant is not None:
quant_data = nifti_mrs_proc.ecc(quant_data, quant_data)
# HLSVD
if args.hlsvd:
......@@ -258,10 +260,10 @@ def main():
if args.leftshift:
if args.verbose:
print('... Truncation ...')
supp_data = nifti_mrs_proc.truncate_or_pad(supp_data, args.leftshift, 'first', report=report_dir)
ref_data = nifti_mrs_proc.truncate_or_pad(ref_data, args.leftshift, 'first')
supp_data = nifti_mrs_proc.truncate_or_pad(supp_data, -args.leftshift, 'first', report=report_dir)
ref_data = nifti_mrs_proc.truncate_or_pad(ref_data, -args.leftshift, 'first')
if args.quant is not None:
quant_data = nifti_mrs_proc.truncate_or_pad(quant_data, args.leftshift, 'first')
quant_data = nifti_mrs_proc.truncate_or_pad(quant_data, -args.leftshift, 'first')
# Apply shift to reference
if args.verbose:
......
......@@ -317,6 +317,14 @@ def main():
if not op.isdir(args.output):
makedirs(args.output)
# Handle report generation output location.
# Bit of a hack, but I messed up the type expected by the
# nifti mrs proc functions.
if args.generateReports:
args.generateReports = args.output
else:
args.generateReports = None
# Call function - pass dict like view of args
# for compatibility with other modules
dataout = args.func(dataList, vars(args))
......@@ -406,17 +414,18 @@ def loadData(datafile, refdatafile=None):
if refdatafile:
loaded_data = datacontainer(NIFTI_MRS(datafile),
datafile,
op.basename(datafile),
NIFTI_MRS(refdatafile),
refdatafile)
op.basename(datafile))
else:
loaded_data = datacontainer(NIFTI_MRS(datafile),
datafile)
op.basename(datafile))
return loaded_data
def writeData(dataobj, args):
if args.filename is None:
fileout = op.join(args.output, dataobj.datafilename)
else:
......
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment