diff --git a/README.md b/README.md index 31055aa..3d28430 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,14 @@ This course is specifically aimed at MSc and PhD students with basic knowledge o * Before seminar you are to install Docker https://www.docker.com/ * SEMINAR 1 (04.09) EEG analysis, Machine Learning in EEG * SEMINAR 2 (04.09) MRI data analysis, sources, databases, tools + * Before seminar, please, do the following: + 1) Download data from link https://drive.google.com/drive/folders/1P0ZhS1EoDY6fncnJb7foNFPjY5uoN6r0?usp=sharing + 2) Clone repository to your local machine + 3) Run docker locally and ensure it working with command `docker run hello-world` + 4) In terminal: `cd to NEUROML/seminar2` + 5) Type command `docker build -t neuroml/seminar2:0.0.1` and wait for successfull build + 6) Run `docker run --rm -it -v /directory/to/downloaded/data:/workspace/data -p 8080:8080 neuroml/seminar2:0.0.1 + 7) Open browser (preferebly Chrome) -> localhost:8080 * Before the seminar you are to install FreeSurfer https://surfer.nmr.mgh.harvard.edu/ * SEMINAR 3 (04.09) Machine Learning for structural MRI data analysis * Before the seminar you are to get an account and granted access here https://db.humanconnectome.org/data/projects/HCP_1200 diff --git a/seminar2/Dockerfile b/seminar2/Dockerfile index 9bcea2f..e563cbb 100644 --- a/seminar2/Dockerfile +++ b/seminar2/Dockerfile @@ -38,11 +38,30 @@ RUN apt-get update -qq \ grep \ less \ wget \ - bzip2 \ make \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* +ENV PATH="/opt/dcm2niix-latest/bin:$PATH" +RUN apt-get update -qq \ + && apt-get install -y -q --no-install-recommends \ + cmake \ + g++ \ + gcc \ + git \ + make \ + pigz \ + zlib1g-dev \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* \ + && git clone https://github.com/rordenlab/dcm2niix /tmp/dcm2niix \ + && mkdir /tmp/dcm2niix/build \ + && cd /tmp/dcm2niix/build \ + && cmake -DCMAKE_INSTALL_PREFIX:PATH=/opt/dcm2niix-latest .. \ + && make \ + && make install \ + && rm -rf /tmp/dcm2niix + ENV ANTSPATH="/opt/ants-2.2.0" \ PATH="/opt/ants-2.2.0:$PATH" RUN echo "Downloading ANTs ..." \ @@ -102,6 +121,7 @@ RUN export PATH="/opt/miniconda-latest/bin:$PATH" \ 'nilearn' \ 'traits' \ 'nipype' \ + 'seaborn' \ && sync && conda clean --all && sync RUN wget https://ftpmirror.gnu.org/parallel/parallel-20190222.tar.bz2 \ @@ -120,8 +140,6 @@ COPY ./entrypoint.sh /entrypoint.sh RUN chmod +x /workspace/multiproc.sh \ /entrypoint.sh - - RUN "/neurodocker/startup.sh" #RUN "./${FREESURFER_HOME}/SetUpFreeSurfer.sh" @@ -142,6 +160,13 @@ RUN echo '{ \ \n ] \ \n ], \ \n [ \ + \n "dcm2niix", \ + \n { \ + \n "version": "latest", \ + \n "method": "source" \ + \n } \ + \n ], \ + \n [ \ \n "ants", \ \n { \ \n "version": "2.2.0" \ diff --git a/seminar2/entrypoint.sh b/seminar2/entrypoint.sh index f06ba16..4ba0ef1 100644 --- a/seminar2/entrypoint.sh +++ b/seminar2/entrypoint.sh @@ -1,9 +1,9 @@ #! /bin/bash -printf 'Neurodocker startup - success' +printf 'Neurodocker startup - success\n' source $FREESURFER_HOME/SetUpFreeSurfer.sh -printf 'FREESURFER - check' +printf 'FREESURFER - check\n' ./opt/miniconda-latest/envs/neuro/bin/jupyter-lab --ip=0.0.0.0 --port=8080 --no-browser --allow-root --notebook-dir='/workspace' --NotebookApp.token='' \ No newline at end of file diff --git a/seminar2/seminar2_1_mri.ipynb b/seminar2/seminar2_1_mri.ipynb index 79be393..fb95e28 100644 --- a/seminar2/seminar2_1_mri.ipynb +++ b/seminar2/seminar2_1_mri.ipynb @@ -1,5 +1,20 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "PLAN:\n", + "\n", + "1) MRI data formats\n", + "2) accessing data voxel and meta data\n", + "3) transformations\n", + "4) preprocessing\n", + "5) visualization\n" + ] + }, { "cell_type": "code", "execution_count": 1, @@ -428,7 +443,45 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "*Voxel size* and *Pixel spacing* are important as we for preprocessing we can use only isomorphic voxel" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Assume that you recieved new dicom from hospital and you need to convert to convinient NIFTI, let's review the tool distinctive from simple on above:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!dcm2niix -o /workspace -f %i_%n_%p -z y /workspace/data/DICOM" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from nilearn.input_data import NiftiMasker\n", + "from nilearn import plotting\n", + "dcm_to_nii_convert = './1010_BRAIN_MR_T1_AX.nii.gz'\n", + "plot_convert = plotting.view_img(dcm_to_nii_convert,\n", + " bg_img=False,\n", + " cmap='gray',\n", + " symmetric_cmap=False,\n", + " threshold=0,\n", + " title='Drag mouse to go through slices')\n", + "plot_convert" + ] } ], "metadata": { @@ -452,4 +505,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/seminar2/seminar2_2_transform.ipynb b/seminar2/seminar2_2_transform.ipynb index cb0bf3d..bb35f20 100644 --- a/seminar2/seminar2_2_transform.ipynb +++ b/seminar2/seminar2_2_transform.ipynb @@ -10,6 +10,13 @@ "warnings.filterwarnings('ignore')\n" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -88,7 +95,7 @@ "mni_space_template = nib.load('/workspace/data/mni_icbm152_t1_tal_nlin_sym_09a.nii') # Full template\n", "\n", "nilearn.plotting.plot_anat(nii_file,\n", - " title='Nifti T1 Native Space')\n", + " title='Nifti T1 Native Space', annotate=True)\n", "\n", "nilearn.plotting.plot_anat(mni_space_template,\n", " title='Nifti MNI152 Space')\n", @@ -154,6 +161,103 @@ "\"\"\".format(nii_file.shape, mni_space_template.shape))\n" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can think of the image affine as a combination of a series of transformations to go from voxel coordinates to mm coordinates in terms of the magnet isocenter. Here is the EPI affine broken down into a series of transformations, with the results shown on the localizer image:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from nibabel.affines import from_matvec, to_matvec, apply_affine\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "reflect = np.array([[1, 0, 0],\n", + " [0, 1, 0],\n", + " [0, 0, 1]])\n", + "\n", + "translate_affine = from_matvec(reflect, [0, 0, 0]) # reflect + shift 10 x direction\n", + "translate_affine" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "transformed = np.dot(nii_file.get_qform(), translate_affine)\n", + "#nii_file.affine = transformed\n", + "print(transformed)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "header_info = nii_file.header\n", + "vox_data = np.array(nii_file.get_fdata())\n", + "transformed_nii = nib.Nifti1Image(vox_data, transformed, header_info)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tranfsorm_image = nilearn.plotting.plot_anat(transformed_nii,\n", + " title='Space displacement', annotate=True)\n", + "tranfsorm_image.add_overlay(nii_file, threshold=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "transform_image = nilearn.plotting.plot_anat(transformed_nii,\n", + " title='Space displacement', annotate=True)\n", + "transform_image.add_overlay(nii_file,threshold=0.8e3, colorbar=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "How about rotation?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "cos_gamma = np.cos(0.3)\n", + "sin_gamma = np.sin(0.3)\n", + "rotation_affine = np.array([[1, 0, 0, 0],\n", + " [0, cos_gamma, -sin_gamma, 0],\n", + " [0, sin_gamma, cos_gamma, 0],\n", + " [0, 0, 0, 1]])" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/seminar2/seminar2_3_freesurfer.ipynb b/seminar2/seminar2_3_freesurfer.ipynb index 538f06d..495941f 100644 --- a/seminar2/seminar2_3_freesurfer.ipynb +++ b/seminar2/seminar2_3_freesurfer.ipynb @@ -1298,6 +1298,59 @@ "my_cmap = matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict,64,1.9)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Let's look at morphological data of freesurfer, particularly thickness data defference between expert options and default options" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import seaborn as sns\n", + "import nibabel\n", + "\n", + "thickness_data = '/workspace/data/fs_preproc/100206/surf/lh.thickness'\n", + "thickness_expert = nibabel.freesurfer.io.read_morph_data(thickness_data)\n", + "\n", + "sns.distplot(thickness_expert, kde_kws={\"color\":\"b\", \"lw\": 2, \"label\":\"thickness_data_expert\"}, hist_kws={\"color\": \"b\"})\n", + "#sns.distplot(thickness_default, kde_kws={\"color\":\"b\", \"lw\": 2, \"label\":\"thickness_data_expert\"}, hist_kws={\"color\": \"b\"})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plot_pial_lh = plotting.view_surf(inflated_path, thickness_data, threshold=0, cmap=my_cmap, black_bg=True)\n", + "plot_pial_lh" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Plot segmentation maps" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plotting.view_img('/workspace/data/fs_preproc/100206/mri/wm.mgz', bg_img='/workspace/data/fs_preproc/100206/mri/brain.mgz',cmap='gray', opacity=0.7)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -1312,9 +1365,10 @@ "\n", "hemi='lh'\n", "subject_id='100206'\n", - "subject_path = '/workspace/'\n", - "inflated_path = os.path.join(subject_path, subject_id, 'surf', hemi + '.pial')\n", - "thickness_data = nibabel.freesurfer.io.read_morph_data(os.path.join(subject_path, patient, 'surf', hemi + '.thickness'))\n", + "subject_path = '/workspace/data/fs_preproc'\n", + "pial_path = os.path.join(subject_path, subject_id, 'surf', hemi + '.pial')\n", + "thickness_data = nibabel.freesurfer.io.read_morph_data(os.path.join(subject_path, subject_id,\n", + " 'surf', hemi + '.thickness'))\n", "inflated_path_1 = os.path.join(subject_path, subject_id, 'surf', 'rh' + '.inflated')" ] }, @@ -1324,9 +1378,63 @@ "metadata": {}, "outputs": [], "source": [ - "plot_pial_lh = plotting.view_surf(inflated_path, thickness_data, threshold=0, cmap=my_cmap, black_bg=True)\n", + "plot_pial_lh = plotting.view_surf(pial_path,\n", + " thickness_data,\n", + " threshold=0,\n", + " cmap=my_cmap)\n", "plot_pial_lh" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "labels, ctab, shape = nibabel.freesurfer.io.read_annot('/workspace/data/fs_preproc/100206/label/lh.aparc.annot')\n", + "plotting.plot_surf_roi(pial_path, roi_map=labels,\n", + " hemi='left', view='lateral',\n", + " bg_on_data=True,\n", + " darkness=.5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "inflated = '/workspace/data/fs_preproc/100206/surf/'\n", + "plot_pial_parc_lh = plotting.view_surf(pial_path,\n", + " labels, cmap='gist_ncar',\n", + " symmetric_cmap=False)\n", + "plot_pial_parc_lh" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Extract features from stats data:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.DataFrame()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": {