{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "FChRVf7Qu-by"
},
"source": [
"# Introduction to fMRI Preprocessing"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "h6VyuYpeu-b2"
},
"source": [
"เนื่องจากบทเรียนนี้จะมีการใช้คำศัพท์ทางเทคนิคและ concept ของ signal processing อยู่พอสมควร ขอให้ผู้เรียนศึกษาเนื้อหาจากบทเรียนของ Brain Code Camp โดยเฉพาะเนื้อหา Signal Processing ก่อนเพื่อให้สามารถทำความเข้าใจเนื้อหาในบทเรียนนี้ได้ง่ายมากขึ้น"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "LZ094AY2u-b3"
},
"source": [
"ในบทเรียนนี้ เราจะนำเอาองค์ความรู้เกี่ยวกับ fMRI ที่เราได้เรียนมาจาก Brain Building Blocks เช่น บทเรียน [fMRI studies](https://youtu.be/ymWZEE1QwfE?si=cgSxi2B_IviHO1-u) และ บทเรียน [fMRI signal](https://youtu.be/wV6rvcpbsvQ?si=oKJH_he6gddi1jHq) มาต่อยอดผ่านการเขียนโค้ดโปรแกรมที่ preprocess ข้อมูล fMRI เบื้องต้น\n",
"\n",
"
\n",
"\n",
"ข้อมูล fMRI เป็นข้อมูลที่โดยทั่วไปมี 4 มิติ (x,y,z,t) ประกอบด้วย\n",
"- spatial dimensions: x, y, z\n",
"- time dimension: t\n",
"\n",
"เราสามารถมองโดยประมาณว่าข้อมูล fMRI คือข้อมูลภาพ MRI 3 มิติ ที่มีแกนเวลาเพิ่มเข้ามา หรือมองเป็น video ของภาพ MRI ก็ได้\n",
"\n",
"ในปัจจุบัน มี software ที่เราสามารถเรียกใช้เพื่อทำการ preprocess หรือวิเคราะห์ข้อมูล fMRI เป็นจำนวนมาก เช่น [FSL](https://www.fmrib.ox.ac.uk/fsl), [Freesurfer](https://surfer.nmr.mgh.harvard.edu), [SPM](https://www.fil.ion.ucl.ac.uk/spm), [fMRIPrep](https://fmriprep.org) และ [QuNex](https://qunex.yale.edu/) แต่ในบทเรียนนี้ เราจะลองเรียกใช้ [FSL](https://www.fmrib.ox.ac.uk/fsl) ใน Python ผ่าน wrapper ที่มีชื่อว่า [fslpy](https://open.win.ox.ac.uk/pages/fsl/fslpy/) เป็นหลัก และเรียกใช้ [nibabel](https://nipy.org/nibabel/) มาช่วยทำบางขั้นตอนด้วย\n",
"\n",
"\n",
"\n",
"
\n",
"\n",
"**หมายเหตุ**\n",
"\n",
"ในบทเรียนนี้เราทำทุกขั้นตอนใน Google Colab สำหรับเป็นตัวอย่างประกอบการเรียนรู้ แต่ในทางปฏิบัตินั้น เรามักใช้ computer server ในการคำนวณเป็นหลัก เนื่องจากข้อมูล fMRI มีจำนวนมิติถึง 4 มิติ ทำให้ต้องใช้พื้นที่จัดเก็บข้อมูลและใช้ทรัพยากรการคำนวณ (computational resource) สูง โดยเฉพาะอย่างยิ่งในกรณีที่เราต้องการ preprocess และวิเคราะห์ข้อมูล fMRI จากหลายหลาย subjects มาเปรียบเทียบกัน\n",
" - ถ้าหากว่าเราใช้พวก command line เป็น เราสามารถใช้ FSL โดยตรงได้เลย ไม่มีความจำเป็นจะต้องใช้ fslpy ก็ได้\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"source": [
"# Tutorial Overview\n",
"\n",
"เวลาเราจะทำการทดลองที่เกี่ยวข้องกับ fMRI เรามักจะเก็บข้อมูลอื่น ๆ เช่น structural MRI หรือ magnetic field map มาควบคู่ไปด้วย เพื่อนำมาใช้ประโยชน์ในหลาย ๆ ด้าน เช่น การนำมาใช้ทำ co-registration และใช้ลด artifacts ได้\n",
"\n",
"ทำให้เราจะต้องทำการ process ข้อมูลหลายประเภทเป็น เช่น\n",
"1. ข้อมูล structural MRI ซึ่งเป็นข้อมูลที่มี spatial resolution ค่อนข้างดี\n",
"2. ข้อมูล functional MRI ซึ่งข้อมูลที่มักจะมี spatial resolution ต่ำกว่า structural MRI มาก แต่มีข้อมูลแกนเวลาเพิ่มเข้ามา\n",
"3. ข้อมูล magnetic field map เช่น B0 map ซึ่งให้ข้อมูลเกี่ยวกับ local magnetic field ของแต่ละตำแหน่ง (x,y,z) ซึ่งสามารถนำเอามาใช้แก้ artifacts ได้ โดยเฉพาะ artifacts ที่เกิดจาก magnetic field inhomogeneity\n",
"\n",
"ในบทเรียนนี้เราจะได้ลองนำเอา structual MRI มาช่วยในการ preprocess และปรับแก้ fMRI ให้มีคุณภาพที่ดีขึ้น พร้อมสำหรับการนำเอาไปวิเคราะห์ผลต่อได้แม่นยำมากยิ่งขึ้น"
],
"metadata": {
"id": "Cl4q1q4g91Ev"
}
},
{
"cell_type": "markdown",
"metadata": {
"id": "7s2pIJJQu-b4"
},
"source": [
"# Setting Up"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "1JYNhwdItgUQ"
},
"source": [
"## Install FSL\n",
"\n",
"ขั้นตอนนี้เราจะลงโปรแกรมชื่อว่า FSL ซึ่งเป็นหนึ่งในโปรแกรมสำหรับ process และ analyze ข้อมูล MRI หลายประเภท (ทั้ง structural, functional และ diffusion) ที่ได้รับความนิยมมาก\n",
"\n",
"ผู้เรียนที่สนใจสามารถดูรายละเอียดการ install เพิ่มเติมได้[ที่นี่](https://fsl.fmrib.ox.ac.uk/fsl/docs/#/install/index)\n",
"\n",
"
\n",
"\n",
"**หมายเหตุ** ขั้นตอนนี้จะกินเวลาค่อนข้างนาน (15 - 25 นาทีบน Google Colab) ซึ่งถ้าเรา install โปรแกรม FSL บนเครื่องคอมพิวเตอร์ส่วนตัวของเรา ก็จะเสียเวลา install ครั้งเดียว แล้วสามารถเรียกใช้งานได้เรื่อย ๆ แต่ถ้าเรารันบน Google Colab ที่เปิด session ใหม่ ก็จะต้องทำขั้นตอนนี้ใหม่\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "7OmylYm4tfhs",
"outputId": "46839a79-fed2-4c52-c28b-6b75968b71bb"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"--2024-09-02 05:47:23-- https://fsl.fmrib.ox.ac.uk/fsldownloads/fslinstaller.py\n",
"Resolving fsl.fmrib.ox.ac.uk (fsl.fmrib.ox.ac.uk)... 129.67.248.66\n",
"Connecting to fsl.fmrib.ox.ac.uk (fsl.fmrib.ox.ac.uk)|129.67.248.66|:443... connected.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 74517 (73K) [application/octet-stream]\n",
"Saving to: ‘fslinstaller.py’\n",
"\n",
"fslinstaller.py 100%[===================>] 72.77K 376KB/s in 0.2s \n",
"\n",
"2024-09-02 05:47:23 (376 KB/s) - ‘fslinstaller.py’ saved [74517/74517]\n",
"\n",
"\u001b[1m\u001b[4mFSL installer version:\u001b[0m 3.2.0\u001b[0m\n",
"\u001b[37mPress CTRL+C at any time to cancel installation\u001b[0m\n",
"\u001b[93m\u001b[1mRunning the installer script as root user is discouraged! You should run this script as a regular user - you will be asked for your administrator password if required.\u001b[0m\n",
"\u001b[37mInstallation log file: /tmp/fslinstaller__j1bai20.log\n",
"\u001b[0m\n",
"\u001b[1m\u001b[4mFSL installer version:\u001b[0m 3.15.1\u001b[0m\n",
"\u001b[37mPress CTRL+C at any time to cancel installation\u001b[0m\n",
"\u001b[93m\u001b[1mRunning the installer script as root user is discouraged! You should run this script as a\n",
"regular user - you will be asked for your administrator password if required.\u001b[0m\n",
"\u001b[37mInstallation log file: /tmp/fslinstaller_pa_tat5h.log\n",
"\u001b[0m\n",
"\u001b[92mInstalling FSL implies agreement with the terms of the FSL license - if you do not agree with\n",
"these terms, you can cancel the installation by pressing CTRL+C.\u001b[0m\u001b[92m You can view the license\n",
"at \u001b[0m\u001b[92m\u001b[4mhttps://fsl.fmrib.ox.ac.uk/fsl/docs/#/license\u001b[0m\n",
"\u001b[0m\n",
"\u001b[37mDuring the installation process, please note that some system details will be automatically\n",
"sent to the FSL development team. These details are extremely basic and cannot be used in any way to\n",
"identify individual users. If you do not want any information to be sent, please cancel this\n",
"installation by pressing CTRL+C, and re-run the installer with the --skip_registration option.\n",
"\u001b[0m\n",
"FSL 6.0.7.13 selected for installation\u001b[0m\n",
"Downloading FSL environment specification from\n",
"https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/releases/fsl-6.0.7.13_linux-64.yml...\u001b[0m\n",
"Downloading FSL environment specification from\n",
"https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/releases/fsl-6.0.7.13_truenet_linux-64.yml...\u001b[0m\n",
"\u001b[1m\n",
"Installing FSL in /usr/local/fsl\n",
"\u001b[0m\n",
"Downloading miniconda from\n",
"https://repo.anaconda.com/miniconda/Miniconda3-py311_24.3.0-0-Linux-x86_64.sh...\u001b[0m\n",
"\u001b[0m\n",
"Installing miniconda at /usr/local/fsl...\u001b[0m\n",
"\u001b[0m\n",
"Installing FSL into /usr/local/fsl...\u001b[0m\n",
"\u001b[0m\n",
"Registering installation with https://fsl.fmrib.ox.ac.uk/fslregistration/\u001b[0m\n",
"\u001b[92m\n",
"FSL successfully installed\n",
"\u001b[0m\n"
]
}
],
"source": [
"!wget https://fsl.fmrib.ox.ac.uk/fsldownloads/fslinstaller.py\n",
"!python fslinstaller.py -d \"/usr/local/fsl\""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "LDgV7ZmxV2Qf"
},
"source": [
"จัดการเรื่อง environment variable เพื่อให้เรียกใช้ FSL ได้"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "QIf1A_pdV1o-"
},
"outputs": [],
"source": [
"# Set environment variables\n",
"import os\n",
"os.environ['FSLDIR'] = '/usr/local/fsl'\n",
"os.environ['FSLOUTPUTTYPE'] = 'NIFTI_GZ'\n",
"os.environ['FSLMULTIFILEQUIT'] = 'TRUE'\n",
"os.environ['FSLTCLSH'] = os.path.join(os.getenv('FSLDIR', ''), 'bin/fsltclsh')\n",
"os.environ['FSLWISH'] = os.path.join(os.getenv('FSLDIR', ''), 'bin/fslwish')\n",
"os.environ['FSL_LOAD_NIFTI_EXTENSIONS'] = '0'\n",
"os.environ['FSL_SKIP_GLOBAL'] = '0'"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "LgFjXncX0vAP"
},
"source": [
"## Install nilearn และ fslpy"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "B1uHBcrd0arG",
"outputId": "2f10981a-b33c-4e4c-9b83-a787694eebd1"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Collecting nilearn\n",
" Downloading nilearn-0.10.4-py3-none-any.whl.metadata (7.8 kB)\n",
"Requirement already satisfied: joblib>=1.0.0 in /usr/local/lib/python3.10/dist-packages (from nilearn) (1.4.2)\n",
"Requirement already satisfied: lxml in /usr/local/lib/python3.10/dist-packages (from nilearn) (4.9.4)\n",
"Requirement already satisfied: nibabel>=4.0.0 in /usr/local/lib/python3.10/dist-packages (from nilearn) (5.0.1)\n",
"Requirement already satisfied: numpy>=1.19.0 in /usr/local/lib/python3.10/dist-packages (from nilearn) (1.26.4)\n",
"Requirement already satisfied: packaging in /usr/local/lib/python3.10/dist-packages (from nilearn) (24.1)\n",
"Requirement already satisfied: pandas>=1.1.5 in /usr/local/lib/python3.10/dist-packages (from nilearn) (2.1.4)\n",
"Requirement already satisfied: requests>=2.25.0 in /usr/local/lib/python3.10/dist-packages (from nilearn) (2.32.3)\n",
"Requirement already satisfied: scikit-learn>=1.0.0 in /usr/local/lib/python3.10/dist-packages (from nilearn) (1.3.2)\n",
"Requirement already satisfied: scipy>=1.8.0 in /usr/local/lib/python3.10/dist-packages (from nilearn) (1.13.1)\n",
"Requirement already satisfied: setuptools in /usr/local/lib/python3.10/dist-packages (from nibabel>=4.0.0->nilearn) (71.0.4)\n",
"Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.10/dist-packages (from pandas>=1.1.5->nilearn) (2.8.2)\n",
"Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas>=1.1.5->nilearn) (2024.1)\n",
"Requirement already satisfied: tzdata>=2022.1 in /usr/local/lib/python3.10/dist-packages (from pandas>=1.1.5->nilearn) (2024.1)\n",
"Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests>=2.25.0->nilearn) (3.3.2)\n",
"Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.25.0->nilearn) (3.8)\n",
"Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests>=2.25.0->nilearn) (2.0.7)\n",
"Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests>=2.25.0->nilearn) (2024.7.4)\n",
"Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from scikit-learn>=1.0.0->nilearn) (3.5.0)\n",
"Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.8.2->pandas>=1.1.5->nilearn) (1.16.0)\n",
"Downloading nilearn-0.10.4-py3-none-any.whl (10.4 MB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m10.4/10.4 MB\u001b[0m \u001b[31m56.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hInstalling collected packages: nilearn\n",
"Successfully installed nilearn-0.10.4\n",
"Collecting fslpy\n",
" Downloading fslpy-3.21.0-py3-none-any.whl.metadata (5.6 kB)\n",
"Collecting dill (from fslpy)\n",
" Downloading dill-0.3.8-py3-none-any.whl.metadata (10 kB)\n",
"Requirement already satisfied: h5py>=2.9 in /usr/local/lib/python3.10/dist-packages (from fslpy) (3.11.0)\n",
"Requirement already satisfied: nibabel>=2.4 in /usr/local/lib/python3.10/dist-packages (from fslpy) (5.0.1)\n",
"Requirement already satisfied: numpy>=1 in /usr/local/lib/python3.10/dist-packages (from fslpy) (1.26.4)\n",
"Requirement already satisfied: scipy>=0.18 in /usr/local/lib/python3.10/dist-packages (from fslpy) (1.13.1)\n",
"Requirement already satisfied: packaging>=17 in /usr/local/lib/python3.10/dist-packages (from nibabel>=2.4->fslpy) (24.1)\n",
"Requirement already satisfied: setuptools in /usr/local/lib/python3.10/dist-packages (from nibabel>=2.4->fslpy) (71.0.4)\n",
"Downloading fslpy-3.21.0-py3-none-any.whl (4.8 MB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m4.8/4.8 MB\u001b[0m \u001b[31m80.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hDownloading dill-0.3.8-py3-none-any.whl (116 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m116.3/116.3 kB\u001b[0m \u001b[31m10.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hInstalling collected packages: dill, fslpy\n",
"Successfully installed dill-0.3.8 fslpy-3.21.0\n"
]
}
],
"source": [
"!pip install nilearn\n",
"!pip install fslpy"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "9pRx5o91_Ll7"
},
"source": [
"## Download ข้อมูลตัวอย่าง"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "l0BVaN09-CMy",
"outputId": "2a94d159-b8ec-485b-ccef-60be60b59837"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Cloning into 'modality-exploration-fMRI'...\n",
"remote: Enumerating objects: 17, done.\u001b[K\n",
"remote: Total 17 (delta 0), reused 0 (delta 0), pack-reused 17 (from 1)\u001b[K\n",
"Receiving objects: 100% (17/17), 160.39 MiB | 35.60 MiB/s, done.\n",
"Updating files: 100% (12/12), done.\n"
]
}
],
"source": [
"!git clone https://github.com/braincodecamp/modality-exploration-fMRI.git\n",
"!mv modality-exploration-fMRI/* .\n",
"!rm -r modality-exploration-fMRI"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "-XtSCSSQ_YHZ"
},
"source": [
"## Import modules ที่จะใช้งาน"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "kHeJ-mgEu-b5",
"scrolled": true
},
"outputs": [],
"source": [
"import nibabel as nib\n",
"from nilearn.plotting import plot_anat, plot_img\n",
"from nilearn.image import index_img\n",
"\n",
"import fsl\n",
"from fsl.data.melodicanalysis import getComponentPowerSpectra, getComponentTimeSeries\n",
"from fsl.wrappers import bet, flirt, fslmaths, mcflirt, fslroi, fslmerge, topup, applytopup, melodic\n",
"\n",
"import numpy as np\n",
"import os\n",
"import matplotlib.pyplot as plt\n",
"from ipywidgets import interact, IntSlider, Dropdown\n",
"import ipywidgets as widgets\n",
"from IPython.display import Image, display"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "MQ1y8FXxDUH8"
},
"source": [
"## เตรียม directories และ ฟังก์ชันสำหรับ visualize ข้อมูล"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Mg2BoooM_cMY"
},
"source": [
"ในการเรียกใช้คำสั่งทั่วไปของ FSL มักจะมีการการอ่านไฟล์และ/หรือเขียนไฟล์เข้ามาเกี่ยวข้องเสมอ ในส่วนนี้เราจึงสร้าง output folder เอามาเก็บไฟล์ที่ถูกสร้างขึ้นในแต่ละขั้นตอนไว้"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "vv2Q4ixOu-b6"
},
"outputs": [],
"source": [
"# กำหนด working directory สำหรับเก็บและวิเคราะห์ข้อมูล\n",
"data_path = 'data' # directory ที่มีข้อมูลที่เราต้องการจะ preprocess\n",
"template_path = 'template' # directory ที่เก็บข้อมูล template\n",
"output_path = 'output' # directory สำหรับเก็บข้อมูลที่ผ่านการประมวลผลแล้ว\n",
"\n",
"# สร้าง output directory\n",
"os.makedirs(output_path, exist_ok=True)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "1KOU9EK1_q4Z"
},
"source": [
"เตรียมฟังก์ชันสำหรับ plot ข้อมูล structural MRI"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "-kXxYGmLu-b7"
},
"outputs": [],
"source": [
"# ฟังก์ชันสำหรับแสดง MRI\n",
"def plot_brain_3D(file_path, slider_name1='Orientation', slider_name2='Slice'):\n",
"\n",
" # โหลดภาพ MRI\n",
" brain_img = nib.load(file_path)\n",
" brain_data = brain_img.get_fdata()\n",
"\n",
" # ฟังก์ชันกำหนดแต่ละ slice\n",
" def plot_slice(axis, slice_idx):\n",
" plt.figure(figsize=(10, 10))\n",
" if axis == 0:\n",
" plt.imshow(brain_data[slice_idx, :, :].T, cmap='gray', origin='lower')\n",
" elif axis == 1:\n",
" plt.imshow(brain_data[:, slice_idx, :].T, cmap='gray', origin='lower')\n",
" elif axis == 2:\n",
" plt.imshow(brain_data[:, :, slice_idx].T, cmap='gray', origin='lower')\n",
" plt.axis('off')\n",
" plt.show()\n",
"\n",
" # สร้าง widget สำหรับเลือกแกนและ slice\n",
" axis_slider = widgets.IntSlider(min=0, max=2, step=1, description=slider_name1)\n",
" slice_slider = widgets.IntSlider(min=0, max=brain_data.shape[2]-1, step=1, description=slider_name2)\n",
"\n",
" def update_slice_range(*args):\n",
" if axis_slider.value == 0:\n",
" slice_slider.max = brain_data.shape[0] - 1\n",
" elif axis_slider.value == 1:\n",
" slice_slider.max = brain_data.shape[1] - 1\n",
" elif axis_slider.value == 2:\n",
" slice_slider.max = brain_data.shape[2] - 1\n",
"\n",
" axis_slider.observe(update_slice_range, 'value')\n",
"\n",
" interact(plot_slice, axis=axis_slider, slice_idx=slice_slider)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "wbo8saZt_wW0"
},
"source": [
"เตรียมฟังก์ชันสำหรับใช้ plot ข้อมูล fMRI"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "yG-vCM-9u-b8"
},
"outputs": [],
"source": [
"# ฟังก์ชันสำหรับแสดง fMRI\n",
"def plot_brain_4D(file_path, slider_name1=\"Orientation\", slider_name2=\"Slice\", slider_name3=\"Time point\"):\n",
"\n",
" # โหลดภาพ MRI\n",
" brain_img = nib.load(file_path)\n",
" brain_data = brain_img.get_fdata()\n",
"\n",
" # ฟังก์ชันกำหนดแต่ละ slice\n",
" def plot_slice(axis, slice_idx, time_idx):\n",
" plt.figure(figsize=(10, 10))\n",
" if axis == 0:\n",
" plt.imshow(brain_data[slice_idx, :, :, time_idx].T, cmap='gray', origin='lower')\n",
" elif axis == 1:\n",
" plt.imshow(brain_data[:, slice_idx, :, time_idx].T, cmap='gray', origin='lower')\n",
" elif axis == 2:\n",
" plt.imshow(brain_data[:, :, slice_idx, time_idx].T, cmap='gray', origin='lower')\n",
" plt.axis('off')\n",
" plt.show()\n",
"\n",
" # สร้าง widget สำหรับเลือกแกน, slice, และเวลา\n",
" axis_slider = widgets.IntSlider(min=0, max=2, step=1, description=slider_name1)\n",
" slice_slider = widgets.IntSlider(min=0, max=brain_data.shape[2]-1, step=1, description=slider_name2)\n",
" time_slider = widgets.IntSlider(min=0, max=brain_data.shape[3]-1, step=1, description=slider_name3)\n",
"\n",
" def update_slice_range(*args):\n",
" if axis_slider.value == 0:\n",
" slice_slider.max = brain_data.shape[0] - 1\n",
" elif axis_slider.value == 1:\n",
" slice_slider.max = brain_data.shape[1] - 1\n",
" elif axis_slider.value == 2:\n",
" slice_slider.max = brain_data.shape[2] - 1\n",
"\n",
" axis_slider.observe(update_slice_range, 'value')\n",
"\n",
" # เพิ่ม interactive plot ด้วยแกน, slice, และเวลา\n",
" interact(plot_slice, axis=axis_slider, slice_idx=slice_slider, time_idx=time_slider)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "41Mz4B0Au-b9"
},
"source": [
"# Structural MRI Preprocessing"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "VmdVH3iFu-b9"
},
"source": [
"ตามที่ได้กล่าวไว้ในตอนต้นของบทเรียน เราสามารถนำเอา structural MRI เช่น T1-weighted (T1w) image และ T2-weighted (T2w) image\n",
"มาใช้ประโยชน์ได้หลายแบบ\n",
"- นำมาวิเคราะห์ค่า imaging derived parameters (IDPs) ในแต่ละ area ที่สนใจได้มากมาย เช่น volume, cortical thickness, surface area และ gyrification\n",
"- นำมาใช้ในการลดหรือแก้ artifacts และ noise (สัญญาณรบกวน)\n",
"- นำมาใช้ในการทำให้ข้อมูลทั้งหมด (ซึ่งอาจจะเก็บมาด้วย resolution ที่ต่างกัน หรือมี orientation ของอวัยวะที่เราเก็บข้อมูลมาไม่ตรงกัน) ให้มีตำแหน่งที่ตรงกัน (co-registration) เพื่อให้สามารถนำมาเปรียบเทียบกันได้ตรงไปตรงมามากขึ้น\n",
"\n",
"
\n",
"\n",
"ใน section นี้เราจะ preprocess ข้อมูล structural MRI แล้วเก็บผลที่ได้เพื่อใช้ประกอบการทำ co-registration กับภาพ fMRI ในภายหลัง โดยมีขั้นตอนโดยสังเขปดังนี้\n",
"1. กำจัดส่วนกะโหลดออก (skull stripping) โดยการใช้ [FSL BET](https://open.win.ox.ac.uk/pages/fslcourse/practicals/intro2/index.html)\n",
"2. Register รูป structural MRI ไปที่รูป template โดยการใช้ [FSL FLIRT](https://web.mit.edu/fsl_v5.0.10/fsl/doc/wiki/FLIRT%282f%29StepByStep.html) เพื่อให้เราสามารถนำเอาข้อมูลจากคนละ subject ซึ่งอาจมีตำแหน่งการเก็บข้อมูลที่แตกต่างกันมาเปรียบเทียบกันได้ดีมากขึ้น ในขั้นตอนนี้เราจะเก็บเอา transformation matrix เอาไว้ใช้ในการ transform ข้อมูล fMRI ในภายหลังด้วย"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "CO6BH1oSu-b-"
},
"outputs": [],
"source": [
"# โหลด raw MRI\n",
"struc = fsl.data.image.Image(os.path.join(data_path, 'struc.nii.gz'))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "PF1eFnJ3u-b-",
"outputId": "911bc198-1466-43a4-d3cd-9ef94e1dfa34"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"(230, 320, 320)"
]
},
"metadata": {},
"execution_count": 10
}
],
"source": [
"# ดูจำนวนมิติของข้อมูล\n",
"struc.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9OWLMbUuu-b_",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 871,
"referenced_widgets": [
"95f6b76dafe14527b1e7fbd1bf6da851",
"ebce1a24116d4998bb2d0af05af28a79",
"587bc5a2fd774153b3a7c035eaf4d157",
"098e06e09f9a4e03a7b7a128e5699e89",
"00d07031d8cf49b88e444f7e1e4aed79",
"7f4d65d036f54e66896bb74b4199e458",
"033ad1a882574091bf5fe70626da5df7",
"52cf1f7640a04b68a889477b3f02d3f2",
"c973748c2e1e44c58ced7cb45a34624b",
"3cde1de141944eedad5699cc666ad093"
]
},
"outputId": "6cf13109-63c7-4d0c-bcbe-fb4ec6971e69"
},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"interactive(children=(IntSlider(value=0, description='Orientation', max=2), IntSlider(value=0, description='Sl…"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "95f6b76dafe14527b1e7fbd1bf6da851"
}
},
"metadata": {}
}
],
"source": [
"# Visualize raw image\n",
"plot_brain_3D(os.path.join(data_path, 'struc.nii.gz'))"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "nz8E_bMn5i8c"
},
"source": [
"## FSL BET for skull stripping"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "I6-37mmT4XuZ"
},
"source": [
"ใช้ FSL BET ในการกำจัดส่วนที่เป็นกะโหลกออกไป ให้เหลือแต่บริเวณสมอง"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "w35es7awu-b_"
},
"outputs": [],
"source": [
"# brain extraction เพื่อตัดกะโหลกออกให้เหลือแต่สมอง แล้ว save ไว้ใน output folder โดยใช้ชื่อไฟล์ว่า struc_brain.nii.gz\n",
"bet_struc = bet(struc, output=os.path.join(output_path, 'struc_brain.nii.gz'), mask=True)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "qPihsdjl4qkN"
},
"source": [
"ดูรูปก่อนที่จะตัดกะโหลกออก โดยเราสามารถปรับค่าได้ 2 ค่าหลัก ๆ\n",
"\n",
"1. ปรับ axis เพื่อดู plane ต่าง ๆ ของข้อมูล MRI เช่น axial, coronal และ sagittal ตามที่ได้เคยเห็นกันมาแล้วในบทเรียน [Data Handling & Exploration](https://youtu.be/SlgIA-lmAwM?si=PZUdRHQY3uKo87lZ) ของ Brain Building Blocks\n",
"2. เลือกตำแหน่งของ slice ที่เราต้องการดูใน plane ที่เราเลือกมา"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "UVV8tkbR4n6X"
},
"source": [
"เปรียบเทียบข้อมูลก่อนและหลังจากที่กำจัดส่วนกะโหลกออกไปแล้ว เพื่อตรวจสอบให้มั่นใจว่า FSL BET ได้ทำหน้าที่ได้อย่างถูกต้อง"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 774
},
"id": "9Hv0deHF5Fu9",
"outputId": "eb63383c-a939-4420-e363-0ac23c260486"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
""
]
},
"metadata": {},
"execution_count": 13
},
{
"output_type": "display_data",
"data": {
"text/plain": [
"