Browse Source

added all of the code necessery

arefks 7 months ago
parent
commit
13cb663094
5 changed files with 257 additions and 34 deletions
  1. 1 1
      code/AIDAmri
  2. 6 0
      code/README.md
  3. 43 0
      code/mask2MTPL.py
  4. 70 33
      code/overlayPlot3D.py
  5. 137 0
      code/register_masks.py

+ 1 - 1
code/AIDAmri

@@ -1 +1 @@
-Subproject commit cc61e0643a7c47322513e133ab8beedfe62967f9
+Subproject commit 8e7f9d3597fecc6fa33093eca5fdd2855e7b22b4

+ 6 - 0
code/README.md

@@ -3,3 +3,9 @@
 This is the code used to process raw Bruker data and to apply transformations from the drawn masks to each individual subject. Note that this is a subdataset linked to the GitHub page of AIDAmri.
 This is the code used to process raw Bruker data and to apply transformations from the drawn masks to each individual subject. Note that this is a subdataset linked to the GitHub page of AIDAmri.
 
 
 The link to the exact branch of the code which was used for this process is: [AIDAmri - SND_Mask_trafu branch](https://github.com/Aswendt-Lab/AIDAmri/tree/SND_Mask_trafu).
 The link to the exact branch of the code which was used for this process is: [AIDAmri - SND_Mask_trafu branch](https://github.com/Aswendt-Lab/AIDAmri/tree/SND_Mask_trafu).
+
+
+
+# Example usage of code
+
+`root@9c22c56092e5:/aida/DATA/code# python mask2MTPL.py -i /aida/DATA/output/Tract_Density -o /aida/DATA/output/Nifti_Tract_density_registered`

+ 43 - 0
code/mask2MTPL.py

@@ -0,0 +1,43 @@
+import os
+import argparse
+import subprocess
+
+def main():
+    parser = argparse.ArgumentParser(description="Resample multiple flo images using a reference image and an affine transformation file.")
+    parser.add_argument("-i", "--input", help="Input folder containing flo images", required=True)
+    parser.add_argument("-o", "--output", help="Output folder for resampled images", required=True)
+    args = parser.parse_args()
+
+    # Get the script's location
+    script_location = os.path.dirname(os.path.realpath(__file__))
+
+    # Construct paths to reference image and affine transformation file
+    ref_image_path = os.path.join(script_location, "..", "output", "C57BL6_mouse.iso_registerd.nii.gz")
+    affine_trafo_path = os.path.join(script_location, "..", "output", "affineTrafo.txt")
+
+    # Create the output folder if it doesn't exist
+    if not os.path.exists(args.output):
+        os.makedirs(args.output)
+
+    # List all flo images in the input folder
+    flo_images = [os.path.join(args.input, image) for image in os.listdir(args.input) if image.endswith(".nii")]
+
+    # Loop through flo images and perform resampling
+    for flo_image in flo_images:
+        output_filename = os.path.basename(flo_image).replace(".nii", "_registered.nii")
+        output_path = os.path.join(args.output, output_filename)
+
+        # Run the resample command
+        command = [
+            "reg_resample",
+            "-ref", ref_image_path,
+            "-flo", flo_image,
+            "-res", output_path,
+            "-trans", affine_trafo_path,
+            "-inter", "0"
+        ]
+
+        subprocess.run(command)
+
+if __name__ == "__main__":
+    main()

+ 70 - 33
code/overlayPlot3D.py

@@ -6,7 +6,7 @@ from scipy.ndimage import rotate
 # Define the file paths
 # Define the file paths
 templateFilePath = r"C:\Users\aswen\Desktop\Code\2024_Ruthe_SND\input\average_template_50_from_website.nii.gz"
 templateFilePath = r"C:\Users\aswen\Desktop\Code\2024_Ruthe_SND\input\average_template_50_from_website.nii.gz"
 densityFilePath = r"C:\Users\aswen\Desktop\Code\2024_Ruthe_SND\input\12_wks_coronal_100141780_50um_projection_density.nii.gz"
 densityFilePath = r"C:\Users\aswen\Desktop\Code\2024_Ruthe_SND\input\12_wks_coronal_100141780_50um_projection_density.nii.gz"
-maskFilePath = r"C:\Users\aswen\Desktop\Code\2024_Ruthe_SND\output\Nifti_Trakte_registered\CC_Mop_dilated_registered.nii.gz"
+maskFilePath = r"\\10.209.5.114\Projects\Student_projects\14_Aref_Kalantari_2021\Luca\CC_Mop_desnitymap_50um.nii.gz"
 
 
 # Load the NIfTI files
 # Load the NIfTI files
 templateNifti = nib.load(templateFilePath)
 templateNifti = nib.load(templateFilePath)
@@ -22,20 +22,64 @@ dpi = 400
 # Get the number of slices along each dimension
 # Get the number of slices along each dimension
 num_slices_dim0, num_slices_dim1, num_slices_dim2 = templateNifti.shape
 num_slices_dim0, num_slices_dim1, num_slices_dim2 = templateNifti.shape
 
 
-# Create a 3D array to hold the overlay
-overlay_volume = np.zeros((num_slices_dim0, num_slices_dim1, num_slices_dim2, 4), dtype=np.uint8)
-
-# Loop through and overlay all slices
-for sliceIdx in range(num_slices_dim2):
-    # Extract the desired slice from the template, density, and mask
-    templateSlice = np.squeeze(templateNifti.get_fdata()[:, :, sliceIdx]).astype(np.uint16)
-    densitySlice = np.squeeze(densityNifti.get_fdata()[:, :, sliceIdx]).astype(np.double)
-    
-    mask_data = maskNifti.get_fdata()
-    mask_data = mask_data.swapaxes(0, 2)
-    mask_data = np.flip(mask_data, axis=0)
-
-    maskSlice = np.squeeze(mask_data[:, :, sliceIdx])
+# Set the slice step for display (every tenth slice)
+slice_step = 10
+
+# Choose the dimension for iteration (0, 1, or 2)
+iteration_dimension = 0  # Change this value to select the dimension
+
+# Calculate the number of rows and columns for the grid based on the selected dimension
+if iteration_dimension == 0:
+    num_slices = num_slices_dim0
+elif iteration_dimension == 1:
+    num_slices = num_slices_dim1
+else:
+    num_slices = num_slices_dim2
+
+grid_size = int(np.sqrt(num_slices // slice_step))
+if grid_size * grid_size < num_slices // slice_step:
+    grid_size += 1
+
+cm = 1/2.54
+# Adjust the figure size to be larger
+fig, axs = plt.subplots(grid_size, grid_size, figsize=(20, 20), dpi=dpi)
+
+# Hide axis numbers
+for ax_row in axs:
+    for ax in ax_row:
+        ax.axis('off')
+
+# Load the mask and perform necessary flips
+mask_data = np.squeeze(maskNifti.get_fdata())
+# Swap the mask over the x and y axes
+mask_data = mask_data.swapaxes(0, 2)
+mask_data = np.flip(mask_data, axis=0)
+
+# Create a new NIfTI image with the adjusted mask data
+adjusted_mask_nifti = nib.Nifti1Image(mask_data, maskNifti.affine)
+
+# Save the new NIfTI image with adjusted header
+output_mask_filepath = r"\\10.209.5.114\Projects\Student_projects\14_Aref_Kalantari_2021\Luca\CC_Mop_desnitymap_50um_reoriented.nii.gz"  # Specify the desired output file path
+nib.save(adjusted_mask_nifti, output_mask_filepath)
+
+# Loop through and display every nth slice as subplots along the selected dimension
+for i, sliceIdx in enumerate(range(0, num_slices, slice_step)):
+    row = i // grid_size
+    col = i % grid_size
+
+    # Extract the desired slice from the template and density based on the selected dimension
+    if iteration_dimension == 0:
+        templateSlice = np.squeeze(templateNifti.get_fdata()[sliceIdx, :, :]).astype(np.uint16)
+        densitySlice = np.squeeze(densityNifti.get_fdata()[sliceIdx, :, :]).astype(np.double)
+        maskSlice = np.squeeze(mask_data[sliceIdx, :, :])
+    elif iteration_dimension == 1:
+        templateSlice = np.squeeze(templateNifti.get_fdata()[:, sliceIdx, :]).astype(np.uint16)
+        densitySlice = np.squeeze(densityNifti.get_fdata()[:, sliceIdx, :]).astype(np.double)
+        maskSlice = np.squeeze(mask_data[:, sliceIdx, :])
+    else:
+        templateSlice = np.squeeze(templateNifti.get_fdata()[:, :, sliceIdx]).astype(np.uint16)
+        densitySlice = np.squeeze(densityNifti.get_fdata()[:, :, sliceIdx]).astype(np.double)
+        maskSlice = np.squeeze(mask_data[:, :, sliceIdx])
 
 
     # Normalize the templateSlice to [0, 1] for visualization
     # Normalize the templateSlice to [0, 1] for visualization
     templateSlice = (templateSlice - np.min(templateSlice)) / (np.max(templateSlice) - np.min(templateSlice))
     templateSlice = (templateSlice - np.min(templateSlice)) / (np.max(templateSlice) - np.min(templateSlice))
@@ -43,25 +87,18 @@ for sliceIdx in range(num_slices_dim2):
     # Overlay the density and mask onto the template slice
     # Overlay the density and mask onto the template slice
     overlayedImage = templateSlice + densitySlice + maskSlice
     overlayedImage = templateSlice + densitySlice + maskSlice
 
 
-    # Normalize the overlay to [0, 1]
-    overlayedImage = (overlayedImage - np.min(overlayedImage)) / (np.max(overlayedImage) - np.min(overlayedImage))
-
-    # Convert the overlay image to RGBA format (4 channels for transparency)
-    overlay_image_rgba = plt.cm.gray(overlayedImage)
-    overlay_image_rgba[:, :, 3] = (overlayedImage * 255).astype(np.uint8)  # Set alpha channel based on intensity
-
-    # Update the 3D overlay volume
-    overlay_volume[:, :, sliceIdx, :] = overlay_image_rgba
-
-# Create a figure for the 3D visualization
-fig = plt.figure(figsize=(10, 10), dpi=dpi)
-ax = fig.add_subplot(111, projection='3d')
+    # Display the overlaid image in the corresponding subplot
+    axs[row, col].imshow(templateSlice, cmap='gray')
+    axs[row, col].imshow(densitySlice, cmap='hot', alpha=0.4)
+    axs[row, col].imshow(maskSlice, cmap='hot', alpha=0.2)  # Apply "hot" colormap to the mask
+  # Apply "cool" colormap to the mask
 
 
-# Plot the 3D overlay volume
-ax.voxels(overlay_volume[:, :, :, 0] > 0, facecolors=overlay_volume[:, :, :, :3] / 255., edgecolor='k')
+# Remove empty subplots if necessary
+for i in range(num_slices // slice_step, grid_size * grid_size):
+    fig.delaxes(axs.flatten()[i])
 
 
-# Set the aspect ratio to be equal for all dimensions
-ax.set_box_aspect([1, 1, 1])
+# Adjust spacing between subplots
+plt.tight_layout()
 
 
-# Show the 3D plot
+# Show the plot
 plt.show()
 plt.show()

+ 137 - 0
code/register_masks.py

@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Jan 12 18:22:18 2024
+
+@author: arefks
+"""
+
+import argparse
+import subprocess
+import shlex
+import os
+import glob
+import csv
+import nibabel as nib
+import numpy as np
+def main():
+    parser = argparse.ArgumentParser(description="Image Registration and Resampling")
+    
+    parser.add_argument("-i", "--input", required=True, help="Path to main folder of the nii Converted Data that are already processed with AIDAmri, e.g proc_data")
+    parser.add_argument("-m", "--masks", required=True, help="Path to the folder containing the drawn masks. They should be in the MTPL space!")
+    
+    args = parser.parse_args()
+    
+    missing_matrix_paths = []
+
+    # Parsing for all BiasBet.nii.gz files in T2w folders after a given input path.
+    T2BetPath = os.path.join(args.input,"**","T2w","*BiasBet.nii.gz")
+    T2BetFiles = glob.glob(T2BetPath,recursive=True)
+    
+    # Parsing for all given masks.
+    FloatingMasksPath = os.path.join(args.masks, "*.nii*")
+    FloatingMasksFiles = glob.glob(FloatingMasksPath)
+    
+    for ff in T2BetFiles:
+        for mm in FloatingMasksFiles:
+            MaskName = os.path.basename(mm).replace(".nii","").replace(".gz","")
+            NewMaskName = MaskName + "_T2w" + ".nii.gz"
+            NewMaskFolder = os.path.join(os.path.dirname(ff),"RegisteredTractMasks")
+            NewMaskAddress = os.path.join(NewMaskFolder,NewMaskName)
+            if not os.path.exists(NewMaskFolder):
+                os.makedirs(NewMaskFolder)
+
+            Affine_matrix_files = glob.glob(os.path.join(os.path.dirname(ff),"*MatrixAff.txt"))
+            if not Affine_matrix_files:
+                missing_matrix_paths.append(os.path.dirname(ff))
+                continue
+            Affine_matrix = Affine_matrix_files[0]
+
+            # Execute the command
+            command = f"reg_resample -ref {ff} -flo {mm} -res {NewMaskAddress} -trans {Affine_matrix} -inter 0"        
+            command_args = shlex.split(command)
+
+            try:
+                result = subprocess.run(command_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+                print(f"Output:\n{result.stdout.decode()}")
+                print(f"Errors:\n{result.stderr.decode()}")
+            except Exception as e:
+                print(f"An error occurred: {e}")
+    
+    print("Registered all masks to t2w space of individual mice: DONE\n")
+    
+    # Parsing for all SmoothMicoBet.nii.gz files in DTI folders after a given input path.
+    DTIBetPath = os.path.join(args.input,"**","DTI*","*SmoothMicoBet.nii.gz")
+    DTIBetFiles = glob.glob(DTIBetPath,recursive=True)
+    
+    for ff in DTIBetFiles:
+        temp = os.path.dirname(os.path.dirname(ff))
+        t2MasksPath = os.path.join(temp,"T2w","RegisteredTractMasks","*nii.gz")
+        FloatingMasksFiles = glob.glob(t2MasksPath)
+        for mm in FloatingMasksFiles:
+            MaskName = os.path.basename(mm).replace("T2w","DTI")
+            NewMaskName = MaskName
+            NewMaskFolder = os.path.join(os.path.dirname(ff),"RegisteredTractMasks")
+            NewMaskAddress = os.path.join(NewMaskFolder,NewMaskName)
+            if not os.path.exists(NewMaskFolder):
+                os.makedirs(NewMaskFolder)
+
+            Affine_matrix_files = glob.glob(os.path.join(os.path.dirname(ff),"*MatrixAff.txt"))
+            if not Affine_matrix_files:
+                missing_matrix_paths.append(os.path.dirname(ff))
+                continue
+            Affine_matrix = Affine_matrix_files[0]
+
+            command = f"reg_resample -ref {ff} -flo {mm} -res {NewMaskAddress} -trans {Affine_matrix} -inter 0"        
+            command_args = shlex.split(command)
+
+            try:
+                result = subprocess.run(command_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+                print(f"Output:\n{result.stdout.decode()}")
+                print(f"Errors:\n{result.stderr.decode()}")
+            except Exception as e:
+                print(f"An error occurred: {e}")
+    
+    # Adjust by flipping for the fa0 and ad files
+    # Locate all files in the "RegisteredTractMasks" folder
+    registered_masks_path = os.path.join(args.input,"**","RegisteredTractMasks", "*.nii.gz")
+    registered_masks_files = glob.glob(registered_masks_path, recursive=True)
+
+    for mask_file in registered_masks_files:
+        # Load the mask file
+        mask_nifti = nib.load(mask_file)
+        mask_data = mask_nifti.get_fdata()
+
+        # Flip the mask along the Y and Z axes
+        #flipped_mask = np.flip(np.flip(mask_data, axis=1), axis=2)
+        flipped_mask = np.flip(mask_data, axis=2)
+        
+
+        # Determine the directory to save the adjusted mask
+        mask_dir = os.path.dirname(os.path.dirname(mask_file))
+        adjusted_masks_dir = os.path.join(mask_dir, "DSI_studio", "RegisteredTractMasks_adjusted")
+
+        # Create the directory if it doesn't exist
+        if not os.path.exists(adjusted_masks_dir):
+            os.makedirs(adjusted_masks_dir)
+
+        # Define the new file name and save the flipped mask
+        adjusted_mask_file = os.path.join(adjusted_masks_dir, os.path.basename(mask_file).replace(".nii.gz","_flipped.nii.gz"))
+        nib.save(nib.Nifti1Image(flipped_mask, mask_nifti.affine), adjusted_mask_file)
+
+        print("Flipping of RegisteredTractMasks and saving to RegisteredTractMasks_adjusted: DONE\n")
+
+    # Save the missing matrix paths to a CSV file
+    missing_matrix_csv_path = os.path.join(args.input, "missing_matrix_paths.csv")
+    with open(missing_matrix_csv_path, mode='w', newline='') as file:
+        writer = csv.writer(file)
+        if not missing_matrix_paths:
+            writer.writerow(["All folders contained an Affine transformation matrix"])
+        else:
+            for path in missing_matrix_paths:
+                writer.writerow([path])
+    
+    print("Saved missing matrix paths to CSV: DONE\n")
+
+        
+if __name__ == "__main__":
+    main()