From 50550816a169765c093dd3119438974befff9b24 Mon Sep 17 00:00:00 2001 From: Julien Cohen-Adad Date: Wed, 17 Jan 2024 13:42:50 -0500 Subject: [PATCH] Compute cord/CSF ratio and removing T1w bloc (#64) Fixes Consider quantifying the ratio cord/CSF signal #63 * Removed T1w block * Put back vertebral labeling on the T2starw scan * Cosmetic changes * Removed temp fix * Create CSF mask * Extract signal in T2starw scan in SC and CSF * Display curves (WIP) * Create curves (only for CoV and CP) * Updated intro --- data_processing.ipynb | 377 +++++++++++------------------------------- 1 file changed, 95 insertions(+), 282 deletions(-) diff --git a/data_processing.ipynb b/data_processing.ipynb index c466d3c..c5fb73a 100644 --- a/data_processing.ipynb +++ b/data_processing.ipynb @@ -5,11 +5,11 @@ "id": "459f60d5", "metadata": {}, "source": [ - "# Analysis code for the paper \"B1+ shimming in the cervical spinal cord at 7T\"\n", + "# Analysis code for the paper \"RF shimming in the cervical spinal cord at 7T\"\n", "\n", "## Data\n", "\n", - "The data can be downloaded at https://openneuro.org/datasets/ds004906\n", + "The data can be downloaded from: https://openneuro.org/datasets/ds004906\n", "\n", "The structure of the input dataset is as follows (JSON sidecars are not listed for clarity):\n", "~~~\n", @@ -56,18 +56,16 @@ "\n", "For each subject:\n", "\n", - "- Segment the spinal cord on GRE scan\n", - "- Label vertebral levels on GRE scan using existing manual disc labels\n", - "- Extract the signal intensity on the GRE scan within the spinal cord\n", - "- Register each B1 map (CP, CoV, etc.) to the GRE scan\n", - "- Apply the computed warping field to bring the segmentation and vertebral levels to the B1 map\n", - "- Convert the B1 map to nT/V units\n", - "- Extract the B1 map value within the spinal cord\n", - "- Segment the spinal cord on the CoV MPRAGE scan\n", - "- Label the vertebral levels using automatic labeling\n", - "- Register the CP mode MPRAGE to the CoV scan\n", - "- Warp segmentation and labeling to the CP mode scan\n", - "- Visualize the CP mode and CoV mode MPRAGE scan, calculate coefficient of variation within the cord for both, plot signal intensity\n", + "- Process anat/T2starw (GRE)\n", + " - Segment the spinal cord (SC)\n", + " - Label vertebral levels using existing manual disc labels\n", + " - Create a mask of the cerebrospinal fluid (CSF)\n", + " - Extract the SC/CSF magnitude signal to assess the stability of the flip angle across shim methods\n", + "- Process fmap/TFL (flip angle maps)\n", + " - Register each B1 map (CP, CoV, etc.) to the GRE scan\n", + " - Apply the computed warping field to bring the segmentation and vertebral levels to the B1 map\n", + " - Convert the B1 map to nT/V units\n", + " - Extract the B1 map value within the SC\n", "\n", ">Slow processes are indicated with the emoji ⏳" ] @@ -187,185 +185,149 @@ }, { "cell_type": "markdown", - "id": "cc07e3e6", + "id": "b0c4e225", "metadata": {}, "source": [ - "## Process anat/T1w (MPRAGE)\n" + "## Process anat/T2starw (GRE)" ] }, { "cell_type": "code", "execution_count": null, - "id": "49a99b31", + "id": "e95d87a4-3194-4369-b6cb-933ad1d5cfa3", "metadata": {}, "outputs": [], "source": [ - "# Run segmentation on CoV_T1w scan, unless it is already in the derivatives/labels\n", + "# Run segmentation on GRE scan\n", + "# ℹ️ The \"CoV reduction\" RF shimming scenario was chosen as the segmentation baseline due to the more \n", + "# homogeneous signal intensity in the I-->S direction, which results in a better segmentation peformance\n", + "# in the C7-T2 region\n", "\n", "for subject in subjects:\n", " os.chdir(os.path.join(path_data, subject, \"anat\"))\n", - " fname_manual_seg = os.path.join(path_labels, subject, \"anat\", f\"{subject}_acq-CoV_T1w_seg.nii.gz\")\n", - " if os.path.exists(fname_manual_seg):\n", - " # Manual segmentation already exists. Copy it to local folder\n", - " print(f\"{subject}: Manual segmentation found\\n\")\n", - " shutil.copyfile(fname_manual_seg, f\"{subject}_acq-CoV_T1w_seg.nii.gz\")\n", - " # Generate QC report to make sure the manual segmentation is correct\n", - " !sct_qc -i {subject}_acq-CoV_T1w.nii.gz -s {subject}_acq-CoV_T1w_seg.nii.gz -p sct_deepseg_sc -qc {path_qc} -qc-subject {subject}\n", + " # Use another syntax for sub-04. See: https://github.com/shimming-toolbox/rf-shimming-7t/issues/31\n", + " if subject == 'sub-04':\n", + " !sct_deepseg_sc -i {subject}_acq-CoV_T2starw.nii.gz -c t2 -qc {path_qc}\n", " else:\n", - " # Manual segmentation does not exist. Run automatic segmentation.\n", - " print(f\"{subject}: Manual segmentation not found\")\n", - " !sct_deepseg_sc -i {subject}_acq-CoV_T1w.nii.gz -c t1 -qc {path_qc}" + " !sct_deepseg_sc -i {subject}_acq-CoV_T2starw.nii.gz -c t2s -qc {path_qc}" ] }, { "cell_type": "code", "execution_count": null, - "id": "663bb98c", - "metadata": { - "scrolled": true - }, + "id": "862dc562", + "metadata": {}, "outputs": [], "source": [ - "# Crop the images for faster processing\n", + "# Crop GRE scan for faster processing and better registration results\n", "\n", "for subject in subjects:\n", " os.chdir(os.path.join(path_data, subject, \"anat\"))\n", - " !sct_crop_image -i {subject}_acq-CoV_T1w.nii.gz -m {subject}_acq-CoV_T1w_seg.nii.gz -dilate 34x34x0 -o {subject}_acq-CoV_T1w_crop.nii.gz\n", - " !sct_crop_image -i {subject}_acq-CoV_T1w_seg.nii.gz -m {subject}_acq-CoV_T1w_seg.nii.gz -dilate 34x34x0 -o {subject}_acq-CoV_T1w_crop_seg.nii.gz" + " !sct_crop_image -i {subject}_acq-CoV_T2starw.nii.gz -m {subject}_acq-CoV_T2starw_seg.nii.gz -dilate 20x20x0 -o {subject}_acq-CoV_T2starw_crop.nii.gz\n", + " !sct_crop_image -i {subject}_acq-CoV_T2starw_seg.nii.gz -m {subject}_acq-CoV_T2starw_seg.nii.gz -dilate 20x20x0 -o {subject}_acq-CoV_T2starw_crop_seg.nii.gz" ] }, { "cell_type": "code", "execution_count": null, - "id": "75071e07", + "id": "87030540", "metadata": {}, "outputs": [], "source": [ - "# Vertebral labeling on the CoV_T1w scan\n", + "# Label vertebrae on GRE scan\n", "\n", - "# Given the low resolution of the GRE scan, the automatic detection of C2-C3 disc is unreliable. Therefore, we \n", - "# need to use the manual disc labels that are part of the dataset.\n", + "# Given the low resolution of the GRE scan, the automatic detection of C2-C3 disc is unreliable. Therefore we need to use the manual disc labels that are part of the dataset.\n", "for subject in subjects:\n", " os.chdir(os.path.join(path_data, subject, \"anat\"))\n", - " fname_label_discs = os.path.join(path_labels, subject, \"anat\", f\"{subject}_acq-CoV_T1w_label-discs_dseg.nii.gz\")\n", - " !sct_label_utils -i {subject}_acq-CoV_T1w_crop_seg.nii.gz -disc {fname_label_discs} -o {subject}_acq-CoV_T1w_crop_seg_labeled.nii.gz\n", + " fname_label_discs = os.path.join(path_data, \"derivatives\", \"labels\", subject, \"anat\", f\"{subject}_acq-CoV_T2starw_label-discs_dseg.nii.gz\")\n", + " !sct_label_utils -i {subject}_acq-CoV_T2starw_crop_seg.nii.gz -disc {fname_label_discs} -o {subject}_acq-CoV_T2starw_crop_seg_labeled.nii.gz\n", " # Generate QC report to assess labeled segmentation\n", - " !sct_qc -i {subject}_acq-CoV_T1w_crop.nii.gz -s {subject}_acq-CoV_T1w_crop_seg_labeled.nii.gz -p sct_label_vertebrae -qc {path_qc} -qc-subject {subject}" + " !sct_qc -i {subject}_acq-CoV_T2starw_crop.nii.gz -s {subject}_acq-CoV_T2starw_crop_seg_labeled.nii.gz -p sct_label_vertebrae -qc {path_qc} -qc-subject {subject}" ] }, { "cell_type": "code", "execution_count": null, - "id": "436a2728", + "id": "c46e8d9a", "metadata": {}, "outputs": [], "source": [ - "# Register the CP_T1w with the CoV_T1w\n", + "# Register *_T2starw to CoV_T2starw\n", "\n", + "# Commenting for now, due to https://github.com/shimming-toolbox/rf-shimming-7t/issues/35\n", "for subject in subjects:\n", " os.chdir(os.path.join(path_data, subject, \"anat\"))\n", - " !sct_register_multimodal -i {subject}_acq-CP_T1w.nii.gz -d {subject}_acq-CoV_T1w_crop.nii.gz -dseg {subject}_acq-CoV_T1w_crop_seg.nii.gz -qc {path_qc}" - ] - }, - { - "cell_type": "markdown", - "id": "a2074892", - "metadata": {}, - "source": [ - "### Verify QC report (T1w segmentation, labeling and registration)\n", - "\n", - "\n", - "Open the QC report located under `ds004906/qc/index.html`. Make sure the registration are correct before resuming the analysis." + " for shim_mode in shim_modes:\n", + " # Don't do it for CoV_T2starw\n", + " if shim_mode != 'CoV':\n", + " !sct_register_multimodal -i {subject}_acq-{shim_mode}_T2starw.nii.gz -d {subject}_acq-CoV_T2starw_crop.nii.gz -dseg {subject}_acq-CoV_T2starw_crop_seg.nii.gz -param step=1,type=im,algo=slicereg,metric=CC -qc {path_qc}" ] }, { "cell_type": "code", "execution_count": null, - "id": "75c43da0", + "id": "eb9a9267", "metadata": {}, "outputs": [], "source": [ - "# Extract the signal intensity on the MPRAGE scan within the spinal cord between levels C3 and T2 (included)\n", + "# Create CSF mask by dilating the spinal cord segmentation\n", "\n", - "for subject in subjects: \n", + "for subject in subjects:\n", " os.chdir(os.path.join(path_data, subject, \"anat\"))\n", - " #CP\n", - " !sct_extract_metric -i {subject}_acq-CP_T1w_reg.nii.gz -f {subject}_acq-CoV_T1w_crop_seg.nii.gz -method wa -vert 3:9 -vertfile {subject}_acq-CoV_T1w_crop_seg_labeled.nii.gz -append 1 -perslice 1 -o {subject}_acq-CP_T1w.csv\n", - " #CoV\n", - " !sct_extract_metric -i {subject}_acq-CoV_T1w_crop.nii.gz -f {subject}_acq-CoV_T1w_crop_seg.nii.gz -method wa -vert 3:9 -vertfile {subject}_acq-CoV_T1w_crop_seg_labeled.nii.gz -append 1 -perslice 1 -o {subject}_acq-CoV_T1w.csv" + " !sct_maths -i {subject}_acq-CoV_T2starw_crop_seg.nii.gz -dilate 3 -shape disk -dim 2 -o {subject}_acq-CoV_T2starw_crop_seg_dilate.nii.gz\n", + " !sct_maths -i {subject}_acq-CoV_T2starw_crop_seg_dilate.nii.gz -sub {subject}_acq-CoV_T2starw_crop_seg.nii.gz -o {subject}_acq-CoV_T2starw_crop_CSFseg.nii.gz\n", + " # Generate QC report to assess CSF mask\n", + " !sct_qc -i {subject}_acq-CoV_T2starw_crop.nii.gz -s {subject}_acq-CoV_T2starw_crop_CSFseg.nii.gz -p sct_deepseg_sc -qc {path_qc} -qc-subject {subject}" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "63e6181a", + "cell_type": "markdown", + "id": "aac9d889", "metadata": {}, - "outputs": [], "source": [ - "# Flattening sagittaly\n", - "for subject in subjects:\n", - " os.chdir(os.path.join(path_data, subject, \"anat\"))\n", - " #flatten \n", - " !sct_flatten_sagittal -i {subject}_acq-CoV_T1w_crop.nii.gz -s {subject}_acq-CoV_T1w_crop_seg.nii.gz\n", - " !sct_flatten_sagittal -i {subject}_acq-CP_T1w_reg.nii.gz -s {subject}_acq-CoV_T1w_crop_seg.nii.gz" + "### Verify QC report (GRE segmentation)\n", + "\n", + "Open the quality control (QC) report located under `ds004906/qc/index.html`. Make sure the spinal cord segmentations are correct before resuming the analysis.\n", + "\n", + ">If you run this notebook on Google Colab, you can skip as the QC report cannot easily be viewed from Google Colab. If you *really* want to see the QC report, you can create a cell where you zip the 'qc/' folder, then you can download it on your local station and open the index.html file. \n" ] }, { "cell_type": "code", "execution_count": null, - "id": "77d24f64", + "id": "90deb5e5", "metadata": {}, "outputs": [], "source": [ - "# Display images\n", + "# Extract the signal intensity on the GRE scan within the spinal cord between levels C3 and T2 (included), which correspond to the region where RF shimming was prescribed\n", "\n", "for subject in subjects:\n", " os.chdir(os.path.join(path_data, subject, \"anat\"))\n", - " CoV_flatten = os.path.join(path_data, subject, \"anat\", f\"{subject}_acq-CoV_T1w_crop_flatten.nii.gz\")\n", - " CoV_flatten_data = nib.load(CoV_flatten).get_fdata()\n", - " CP_flatten = os.path.join(path_data, subject, \"anat\", f\"{subject}_acq-CP_T1w_reg_flatten.nii.gz\")\n", - " CP_flatten_data=nib.load(CP_flatten).get_fdata()\n", - "\n", - " # Data manipulation to get the central slice\n", - " # Already cropped inf-sup and right-left, no need to crop more\n", - " CoV_flatten_data_cslice=CoV_flatten_data[CoV_flatten_data.shape[0] // 2,:,:]\n", - " CP_flatten_data_cslice=CP_flatten_data[CP_flatten_data.shape[0] // 2,:,:]\n", - " #And now plot side by side\n", - " plt.figure(figsize=(3, 4))\n", - " vmin = -1 \n", - " vmax = -0.70\n", - "\n", - " plt.subplot(1, 2, 1)\n", - " plt.imshow(CP_flatten_data_cslice.T, cmap='gray', origin='lower',vmin=vmin,vmax=vmax) \n", - " plt.title('CP mode',color='blue')\n", - " plt.axis('off')\n", - "\n", - " plt.subplot(1, 2, 2)\n", - " plt.imshow(CoV_flatten_data_cslice.T, cmap='gray', origin='lower',vmin=vmin, vmax=vmax)\n", - " plt.title('CoV reduction',color='orange')\n", - " plt.axis('off')\n", - "\n", - " # Add the subject title at the top\n", - " plt.suptitle(subject, y=0.9) # Adjust 'y' as needed for position\n", - " plt.tight_layout()\n", - " plt.subplots_adjust(wspace=0.1, hspace=0)\n", - " plt.show() " + " for shim_method in ['CoV', 'CP']: # TODO: shim_modes:\n", + " # Shim methods are registered to the CoV T2starw scan, so we need to use the added suffix to identify them\n", + " if shim_method == 'CoV':\n", + " file_suffix = 'crop'\n", + " else:\n", + " file_suffix = 'reg'\n", + " fname_result_sc = os.path.join(path_results, f\"{subject}_acq-{shim_method}_T2starw_label-SC.csv\")\n", + " !sct_extract_metric -i {subject}_acq-{shim_method}_T2starw_{file_suffix}.nii.gz -f {subject}_acq-CoV_T2starw_crop_seg.nii.gz -method wa -vert 3:9 -vertfile {subject}_acq-CoV_T2starw_crop_seg_labeled.nii.gz -perslice 1 -o {fname_result_sc}\n", + " fname_result_csf = os.path.join(path_results, f\"{subject}_acq-{shim_method}_T2starw_label-CSF.csv\")\n", + " !sct_extract_metric -i {subject}_acq-{shim_method}_T2starw_{file_suffix}.nii.gz -f {subject}_acq-CoV_T2starw_crop_CSFseg.nii.gz -method wa -vert 3:9 -vertfile {subject}_acq-CoV_T2starw_crop_seg_labeled.nii.gz -perslice 1 -o {fname_result_csf}" ] }, { "cell_type": "code", "execution_count": null, - "id": "cd2a3c9c", + "id": "a00909b8", "metadata": {}, "outputs": [], "source": [ - "# Generate signal intensity curves\n", - "# Make figure of B1+ values along the spinal cord across shim methods\n", + "# Make figure of SC/CSF signal ratio from T2starw scan\n", "\n", "# Go back to root data folder\n", - "os.chdir(os.path.join(path_data))\n", + "os.chdir(path_data)\n", "\n", - "def smooth_data(data, window_size=11):\n", + "def smooth_data(data, window_size=20):\n", " \"\"\" Apply a simple moving average to smooth the data. \"\"\"\n", " return uniform_filter1d(data, size=window_size, mode='nearest')\n", "\n", @@ -373,7 +335,7 @@ "x_grid = np.linspace(0, 1, 100)\n", "\n", "# z-slices corresponding to levels C1 to T2 on the PAM50 template. These will be used to scale the x-label of each subject.\n", - "original_vector =np.array([907, 870, 833, 800, 769, 735, 692, 646]) # np.array([984, 938, 907, 870, 833, 800, 769, 735, 692, 646])\n", + "original_vector = np.array([984, 938, 907, 870, 833, 800, 769, 735, 692, 646])\n", "\n", "# Normalize the PAM50 z-slice numbers to the 1-0 range (to show inferior-superior instead of superior-inferior)\n", "min_val = original_vector.min()\n", @@ -397,28 +359,35 @@ "# Iterate over each subject and create a subplot\n", "for i, subject in enumerate(subjects):\n", " ax = axes[i]\n", - " \n", - " os.chdir(os.path.join(path_data, subject, \"anat\"))\n", "\n", - " for shim_method in shim_modes_MPRAGE:\n", + " for shim_method in ['CoV', 'CP']: # TODO: shim_modes:\n", " # Initialize list to collect data for this shim method\n", " method_data = []\n", "\n", - " for file_path in glob.glob(f\"{subject}_acq-{shim_method}_T1w.csv\"):\n", - " df = pd.read_csv(file_path)\n", - " wa_data = df['WA()']\n", + " # Get signal in SC\n", + " file_csv = os.path.join(path_results, f\"{subject}_acq-{shim_method}_T2starw_label-SC.csv\")\n", + " df = pd.read_csv(file_csv)\n", + " data_sc = df['WA()']\n", "\n", - " # Normalize the x-axis to a 0-1 scale for each subject\n", - " x_subject = np.linspace(0, 1, len(wa_data))\n", + " # Get signal in CSF\n", + " file_csv = os.path.join(path_results, f\"{subject}_acq-{shim_method}_T2starw_label-CSF.csv\")\n", + " df = pd.read_csv(file_csv)\n", + " data_csf = df['WA()']\n", + " \n", + " # Compute ratio\n", + " data_sc_csf_ratio = data_sc / data_csf\n", "\n", - " # Interpolate to the fixed grid\n", - " interp_func = interp1d(x_subject, wa_data, kind='linear', bounds_error=False, fill_value='extrapolate')\n", - " resampled_data = interp_func(x_grid)\n", + " # Normalize the x-axis to a 0-1 scale for each subject\n", + " x_subject = np.linspace(0, 1, len(data_sc_csf_ratio))\n", "\n", - " # Apply smoothing\n", - " smoothed_data = smooth_data(resampled_data)\n", + " # Interpolate to the fixed grid\n", + " interp_func = interp1d(x_subject, data_sc_csf_ratio, kind='linear', bounds_error=False, fill_value='extrapolate')\n", + " resampled_data = interp_func(x_grid)\n", "\n", - " method_data.append(smoothed_data)\n", + " # Apply smoothing\n", + " smoothed_data = smooth_data(resampled_data)\n", + "\n", + " method_data.append(smoothed_data)\n", "\n", " # If there's data for this shim method, plot it\n", " if method_data:\n", @@ -431,7 +400,7 @@ " ax.set_xticklabels([''] * len(original_vector))\n", "\n", " ax.set_title(f'{subject}', fontsize=font_size)\n", - " ax.set_ylabel('Signal intensity [a.u.]', fontsize=font_size)\n", + " ax.set_ylabel('Cord/CSF T2starw signal ratio', fontsize=font_size)\n", " ax.tick_params(axis='y', which='major', labelsize=font_size-4)\n", "\n", " # Add legend only to the first subplot\n", @@ -445,162 +414,6 @@ "plt.show()" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "1a690f03", - "metadata": {}, - "outputs": [], - "source": [ - "# Create mean and CoV \n", - "\n", - "# Go back to root data folder\n", - "os.chdir(path_data)\n", - "\n", - "# Data storage\n", - "data_summary = []\n", - "\n", - "# Compute mean and SD of MPRAGE sigint for each subject and each shim mode\n", - "for subject in subjects:\n", - " for shim_mode in shim_modes_MPRAGE:\n", - " all_data = []\n", - " for file_path in glob.glob(os.path.join(path_data, subject, \"anat\", f\"{subject}_acq-{shim_mode}_T1w.csv\")):\n", - " # print(file_path)\n", - " df = pd.read_csv(file_path)\n", - " wa_data = df['WA()']\n", - " all_data.extend(wa_data)\n", - "\n", - " if all_data:\n", - " mean_data = np.mean(all_data)\n", - " sd_data = np.std(all_data)\n", - " CoV_data=np.round((sd_data/mean_data)*100,2)\n", - " data_summary.append([subject, shim_mode, mean_data, sd_data, CoV_data])\n", - "\n", - "# Convert to DataFrame and save to CSV\n", - "df_summary = pd.DataFrame(data_summary, columns=['Subject', 'Shim_Mode', 'Average', 'Standard_Deviation', 'CoV'])\n", - "df_summary.to_csv(os.path.join(path_results, 'subject_shim_mode_summary.csv'), index=False)\n", - "\n", - "df_summary_onlyCoV=df_summary[['Subject', 'Shim_Mode', 'CoV']]\n", - "print(df_summary_onlyCoV)\n" - ] - }, - { - "cell_type": "markdown", - "id": "b0c4e225", - "metadata": {}, - "source": [ - "## Process anat/T2starw (GRE)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e95d87a4-3194-4369-b6cb-933ad1d5cfa3", - "metadata": {}, - "outputs": [], - "source": [ - "# Run segmentation on GRE scan\n", - "# ℹ️ The \"CoV reduction\" RF shimming scenario was chosen as the segmentation baseline due to the more \n", - "# homogeneous signal intensity in the I-->S direction, which results in a better segmentation peformance\n", - "# in the C7-T2 region\n", - "\n", - "for subject in subjects:\n", - " os.chdir(os.path.join(path_data, subject, \"anat\"))\n", - " # Use another syntax for sub-04. See: https://github.com/shimming-toolbox/rf-shimming-7t/issues/31\n", - " if subject == 'sub-04':\n", - " !sct_deepseg_sc -i {subject}_acq-CoV_T2starw.nii.gz -c t2 -qc {path_qc}\n", - " else:\n", - " !sct_deepseg_sc -i {subject}_acq-CoV_T2starw.nii.gz -c t2s -qc {path_qc}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "862dc562", - "metadata": {}, - "outputs": [], - "source": [ - "# Crop GRE scan for faster processing and better registration results\n", - "\n", - "for subject in subjects:\n", - " os.chdir(os.path.join(path_data, subject, \"anat\"))\n", - " !sct_crop_image -i {subject}_acq-CoV_T2starw.nii.gz -m {subject}_acq-CoV_T2starw_seg.nii.gz -dilate 20x20x0 -o {subject}_acq-CoV_T2starw_crop.nii.gz\n", - " !sct_crop_image -i {subject}_acq-CoV_T2starw_seg.nii.gz -m {subject}_acq-CoV_T2starw_seg.nii.gz -dilate 20x20x0 -o {subject}_acq-CoV_T2starw_crop_seg.nii.gz" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "87030540", - "metadata": {}, - "outputs": [], - "source": [ - "# Register CoV_T2starw to CoV_T1w to bring vertebral labels\n", - "\n", - "for subject in subjects:\n", - " os.chdir(os.path.join(path_data, subject, \"anat\")) \n", - " !sct_register_multimodal -i {subject}_acq-CoV_T1w_crop.nii.gz -iseg {subject}_acq-CoV_T1w_crop_seg.nii.gz -d {subject}_acq-CoV_T2starw_crop.nii.gz -dseg {subject}_acq-CoV_T2starw_crop_seg.nii.gz -param step=1,type=seg,algo=slicereg -qc {path_qc}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c46e8d9a", - "metadata": {}, - "outputs": [], - "source": [ - "# Register *_T2starw to CoV_T2starw\n", - "\n", - "# Commenting for now, due to https://github.com/shimming-toolbox/rf-shimming-7t/issues/35\n", - "# for subject in subjects:\n", - "# os.chdir(os.path.join(path_data, subject, \"anat\"))\n", - "# for shim_mode in shim_modes:\n", - "# # Don't do it for CoV_T2starw\n", - "# if shim_mode != 'CoV':\n", - "# !sct_register_multimodal -i {subject}_acq-{shim_mode}_T2starw.nii.gz -d {subject}_acq-CoV_T2starw_crop.nii.gz -dseg {subject}_acq-CoV_T2starw_crop_seg.nii.gz -param step=1,type=im,algo=slicereg,metric=CC -qc {path_qc}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0ffcfb28", - "metadata": {}, - "outputs": [], - "source": [ - "# Warp vertebral level to *_T2starw\n", - "\n", - "for subject in subjects:\n", - " os.chdir(os.path.join(path_data, subject, \"anat\")) \n", - " !sct_apply_transfo -i {subject}_acq-CoV_T1w_crop_seg_labeled.nii.gz -d {subject}_acq-CoV_T2starw_crop.nii.gz -w warp_{subject}_acq-CoV_T1w_crop2{subject}_acq-CoV_T2starw_crop.nii.gz -x nn -o {subject}_acq-CoV_T2starw_crop_seg_labeled.nii.gz" - ] - }, - { - "cell_type": "markdown", - "id": "aac9d889", - "metadata": {}, - "source": [ - "## Verify QC report (GRE segmentation)\n", - "\n", - "Open the quality control (QC) report located under `ds004906/qc/index.html`. Make sure the spinal cord segmentations are correct before resuming the analysis.\n", - "\n", - ">If you run this notebook on Google Colab, you can skip as the QC report cannot easily be viewed from Google Colab. If you *really* want to see the QC report, you can create a cell where you zip the 'qc/' folder, then you can download it on your local station and open the index.html file. \n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "90deb5e5", - "metadata": {}, - "outputs": [], - "source": [ - "# Extract the signal intensity on the GRE scan within the spinal cord between levels C3 and T2 (included), which correspond to the region where RF shimming was prescribed\n", - "\n", - "for subject in subjects:\n", - " # TODO: loop across other shim methods \n", - " os.chdir(os.path.join(path_data, subject, \"anat\"))\n", - " !sct_extract_metric -i {subject}_acq-CoV_T2starw_crop.nii.gz -f {subject}_acq-CoV_T2starw_crop_seg.nii.gz -method wa -vert 3:9 -vertfile {subject}_acq-CoV_T2starw_crop_seg_labeled.nii.gz -append 1 -perslice 1 -o gre_CoV.csv\n" - ] - }, { "cell_type": "markdown", "id": "bda7c3ac", @@ -629,7 +442,7 @@ "id": "39de4623", "metadata": {}, "source": [ - "## Verify QC report (B1maps to GRE registration)\n", + "### Verify QC report (B1maps to GRE registration)\n", "\n", "Open the QC report located under `ds004906/qc/index.html`. Make sure the registration are correct before resuming the analysis." ]