<jupyter_start><jupyter_text>Matricule & noms :  Ce  lien vous permettra de voir les différences fondamentales entre Python et Matlab. Ne passez pas forcement par les étapes d'installation. La cellule ci dessous effectue des import cela s'assimile a unaddpath en matlab. Le but est d'amener des fonctions extérieures (packages) dans le notebook afin que Python les reconnaisse.   import package as pkg permet de raccourcir le nom de ce dernier. Les fonctions contenues dans 'package' seront alors appelées ainsi pkg.function()    Vous pouvez chercher sur google chacun des package appelés ci-dessous afin d'obtenir leur documentation.N'oubliez pas de relancer cette cellule si jamais vous redemarrez le Kernel !!<jupyter_code>import nibabel as nib
import pydicom as pycd
import matplotlib.pyplot as plt
import math
import dicom
from numpy.fft import *
from numpy import matlib as mb
import numpy as np
import copy
from niwidgets import NiftiWidget
import nilearn.plotting as nip

%matplotlib inline<jupyter_output><empty_output><jupyter_text>Partie I : Concepts d'imagerie    1. Lecture de l’image DICOMLes images issues du système IRM sont sous format DICOM (extension .dcm). DICOM est un standard de fichier en imagerie médicale (pas seulement pour l'IRM, mais aussi pour le PET, CT, US, etc.). Les fichiers DICOM incluent un header qui contient des informations ou "metadata" sur l'acquisition des images (e.g., date de l'examen, modèle d'IRM, TR, TE, angle de flip, position des slices, etc.), suivi de l'image encodée en binaire. Une image 3D est sauvegardée sous plusieurs tranches, i.e. plusieurs fichiers DICOM.    Ci-dessous, nous analyserons le contenu du fichier DICOM FourierTransform_Test01-03-0011.dcm, notamment nous afficherons l'image et nous analyserons quelques champs des metadata.<jupyter_code># La ligne ci-dessous sert à lire l'image DICOM et à la mettre dans la variable dcm
dcm = dicom.read_file('dicom/FourierTransform_Test01-03-0011.dcm', force=True)

# L'attribut "pixel_array" sert à récupérer l'image (i.e. matrice 2d)
image = dcm.pixel_array

# Afficher l'image
plt.figure(figsize=(10,10))
plt.imshow(image)
plt.show()<jupyter_output><empty_output><jupyter_text>A) Quelle est la largeur de la coupe (en z) ? Quelle est l'unité ? 1pt    Pour afficher le contenu d'une variable en Python, vous pouvez utiliser la fonction print(dcm).     Sélectionner ensuite le champ pertinent : dcm.CHAMPATTENTION: Les espaces doivent être enlevés pour appeler le champ. Exemple: "Study Date" --> dcm.StudyDate<jupyter_code># Utilisez cette cellule pour votre code. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>**double click here to add your answer** B) Étant donné que nous imageons des protons 1H et que le champ est 3 teslas, estimezapproximativement la valeur du gradient magnétique qui est imposé en z pour former unetranche de cette largeur si nous supposons que la largeur de bande de l’impulsion RF estde 1 kHz. 2pts<jupyter_code># Utilisez cette cellule pour effectuer vos calculs. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>**double click here to add your answer**      2. Analyse de Fourier Rappelons que le signal acquis en IRM est en fait la transformée de Fourier de l’image (voir les équations 13.46 et 13.47 du livre de Prince & Links). L’image du cerveau qu’on affiche est donc la transformée inverse des données.    Le code ci-dessous permet d'ouvrir l'image de phase et d'afficher l'image de magnitude et de phase. Pour plus d'information visiter la page de la documentation ici.<jupyter_code># On ouvre l'image de phase
dcm_phase = dicom.read_file('dicom/FourierTransform_Test01-04-0011.dcm', force=True)
image_phase = dcm_phase.pixel_array

#  Display. Le package utilisé est matplotlib.pyplot qui a été importé en tant que plt. Nous appelons donc les fonction plt.fonction
plt.figure(figsize = (10, 10))  # plt.figure permet de décrire l'image. "figsize" détermine la taille de la figure.
plt.subplot(1, 2, 1)  # permet de créer un subplot. La numerotation est la suivante (nb_colonne,nb_lignes,index) 
# L'indexation commence a 1 et va de gauche a droite et de haut en bas. 
plt.imshow(image)  # équivalent de la fonction imagesc
plt.title('Image de magnitude')  # le titre s'applique a l'objet subplot, en l'occurence le dernier existant. 
plt.subplot(1, 2, 2)
plt.imshow(image_phase, cmap="jet")
plt.title('Image de phase')
plt.show()  # permet d'afficher l'image.<jupyter_output><empty_output><jupyter_text>Les limitations d’acquisition liées au phénomène de Nyquist s’opèrent ici dans l’espacedes fréquences spatiales. Pour étudier ce phénomène suivez les instructions ci dessous :● Faites la transformée de Fourier 2D (fonction fft2) de l’image de magnitude FourierTransform_Test01-03-0011.dcm.● Sous-échantillonnez cette transformée par un facteur 2 selon les deux axes (u et v).Pour conserver la taille de la matrice (256x256), remplacer une ligne sur deux par des 0.   ● Faites la transformée inverse. ATTENTION: En python l'indexation commence à 0.Les matrices sont definies comme suit m=[[0,0],[1,1]]. Ceci donne une matrice avec une premiere ligne de 0 et une seconde ligne de 1.L'equivalent de repmat en Python se trouve dans numpy.matlib, que nous avons importé comme : mb. La fonction est donc : mb.repmat(m,Nb_ligne,Nb_colonne)Pour notre matrice 'm' la taille peut être obtenue à l'aide de m.shape qui renverra (2,2).Les fonctions de type abs,real Peuvent être utilisées comme en Matlab.  2.2. Illustrez l’image ainsi obtenue. Comparez-la avec l’image originale. Expliquez lephénomène observé et sa cause. 3pts<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>Recommencez avec l’image originale :- Faites sa transformée de Fourier 2D.- Sous-échantillonnez cette transformée par un facteur 2 selon les deux axes (u et v).Cette fois-ci, retirez un élément sur deux (en u et v, donc 1 ligne sur 2 et 1 colonnesur 2). Vous diminuerez donc de moitié la taille de votre matrice dans chaquedimension.- Faites la transformée inverse.Illustrez l’image ainsi obtenue. Comparez-la avec l’image originale et avecl’image reconstruite à la question 2.2. Expliquez les différences observées. 3pts   Pour faire cela regardez les possibilités de slicing en Python. ce tutorial vous permettra de voir les bases. Cependant vous êtes encouragé à chercher sur internet.Il est également possible de proposer une version plus algorithmique.<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>**double click here to add your answer** 2.3. Comment l’acquisition dans l’espace Fourier affecte la résolution spatiale de l'image ? Décrire l'équation qui régit la résolution spatiale en fonction des paramètres d'instrumentation de l'IRM. Quelles sont les contraintes d'instrumentation et de sécurité/confort du patient qui limitent la résolution spatiale ? 3pts     **double click here to add your answer**    3. ArtéfactsCette section a pour but de vous faire simuler 2 artéfacts qui peuvent survenir de manière assezfréquente lors de l’acquisition d’une image par résonance magnétique : artefact de « spiking » et artefact de mouvement.3.1.1. Artefact de Spiking. Décrivez une procédure permettant de simuler un artéfact « spiking » à partir d’une image déjà reconstruite. Comment cet artéfact affecte-t-il l’image finale ? 1.5pts     **double click here to add your answer**     3.1.2. Implémentez cette procédure en utilisant FourierTransform_Test01-03-0011.dcm et simulez trois types de spiking artefacts : horizontal, vertical et oblique.  1.5pts ATTENTION : Comment copier une matrice d'une variable vers une autre variable dans Python.Illustration avec le code suivant :        a = [0, 0]    b = a    b[0] = 1    print(a[0])    >> 1   au lieu de 0 !!!Cela est dû au fait que cette opération repose sur des pointeurs.La solution pour éviter cela est d'utiliser la fonction deepcopy :     import copy    b = copy.deepcopy(a)Cela pourra vous être utile pour copier la matrice afin de simuler plusieurs artefacts.Si vous souhaitez revenir dans le k-space, utilisez une transformée de Fourier inverse :    ifft2Ne pas oublier de prendre en compte le shift.<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>3.2.1. Artefact de mouvement. Toujours à partir de la même image, observez l'effet d'un mouvement de l'image sur sa transformée de Fourier :    - Décalez votre image de 10 pixels (fonction np.roll dont vous trouverez la documentation ici).- Calculez le k-space de l’image originale et de l’image décalée<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>Observez-vous une différence sur la magnitude du k-space? Sur la phase duk-space? Commentez (indiquez aussi pourquoi la phase du k-space est en « arcen ciel »).2pts         **double click here to add your answer** 3.2.2. Décrivez une procédure permettant de simuler un artéfact correspondant à unmouvement global du patient en cours d’acquisition. 1pt     **double click here to add your answer**   3.2.3. Implémentez cette procédure pour un mouvement de 10 pixels dans la direction de votrechoix. Considérez deux cas : (i) la deuxième moitié du k-space est affectée par lemouvement et (ii) une ligne du k-space sur deux est affectée par le mouvement.Expliquez vos résultats.2pts<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>**double click here to add your answer**  Partie II : IRM anatomique      4. Étude de l'image anatomique D'autres formats d'images sont souvent utilisés en IRM, par exemple le format NIfTI (.nii).Chargez l’image anatomique anat/mprage.nii.gz en utilisant nib.load.<jupyter_code>nii = nib.load('anat/mprage.nii.gz')<jupyter_output><empty_output><jupyter_text>4.1. Il s’agit d’une image à 3 dimensions. Quelle est le nombre de voxels dans chacune desdimensions ? Quelle est la taille de chaque voxel (en mm) ? Indice : regarder lastructure de pixdim dans nii.header 1pt     nib.load renvoie un objet nifti constitué d'un header et de l'image. Utilisez objet.header pour acceder au header et object.dataobj pour acceder au données d'image.<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>**double click here to add your answer** Visualisez l’image à l'aide de la cellule ci-dessous. Cette image a été prise avec une séquence 3D de typeécho de gradient (gradient echo). Le TR est très faible (inférieur à 10ms), il s’agit donc d’une image pondérée en T1. Un pulse d’inversion-récupération prépare les spins afin d’augmenter le contraste entre les tissus(suppression du liquide cérébrospinal). Le nom de cette séquence est « MPRAGE ». 4.2. Faites une capture d'écran (screenshot) de la vue axiale (seulement la vue axiale).Quelle est cette structure noire située aux coordonnées (-10, -22, 28) ? Quelle stratégiea permis d’annuler le signal pour cette structure ? 2pts    Vous pouvez vous deplacer sur l'image à l'aide de la souris.En cas de problème avec le viewer (l'image apparait hachée), cliquez sur une des vues correctes et cela reviendra à la normale.<jupyter_code># Visualiser l'image en utilisant nilearn plotting
nip.view_img(nii, cut_coords=[0, 0, 0], title="anatomical image", cmap="gray", symmetric_cmap=False, bg_black=True, bg_image=False)<jupyter_output><empty_output><jupyter_text>**double click here to add your answer** 4.3. A quoi correspond le petit blob gris aux coordonnées (56,68,28) ? 2pts     **double click here to add your answer** 4.4. Observez la structure très brillante aux coordonnées (-2,-6,-14). Il s’agit de l’artèrebasilaire. Pourquoi lesignal de celle-ci n’a pas été supprimé comme en 4.2? 2pts     **double click here to add your answer**  Partie III : IRM fonctionnelle (IRMf ou fMRI)      5. Étude des images fonctionnellesNous allons étudier l'image fmri.niiLa particularité de ce fichier est qu’il s’agit d’une image 4D (versus 3D pour l’image anatomique).Les dimensions (x,y,z,t) de l’image sont : 64×64×21×180. Cela implique qu’il y a 180 volumes 3D,un volume étant mesuré toutes les TR secondes. Ici, le temps de répétition TR = 3 secondes .    La séquence utilisée pour acquérir ces volumes est une séquence en écho de gradient, pondéréeen T2\*, utilisant la technique echo planar imaging (EPI). L’intérêt d’utiliser la technique EPI estd’obtenir un volume du cerveau complet très rapidement. Ici, chaque volume est acquis enseulement 3 secondes !! Par comparaison, le volume anatomique précédent a été acquis en 5minutes. Bien sûr, la qualité d’image est moindre.    Affichons l'image.<jupyter_code># Afficher l'image en utilisant NiftiWidget.nifti_plotter().
# Note: Utilisez les sliders pour vous déplacer. Une fois que vous avez cliqué sur un slider, vous pouvez utiliser
# les flèches gauche/droite pour bouger le slider.
fmri_widget = NiftiWidget('fmri/fmri.nii.gz')
fmri_widget.nifti_plotter(colormap='nipy_spectral', display_mode=['ortho', 'xz'])<jupyter_output><empty_output><jupyter_text>5.1.1 Comment se fait-il que le cerveau apparaisse "applati" dans la direction supérieure-inférieure ?    Tips: Étudiez le header de l'image NIfTI en l'ouvrant avec nibabel.<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>5.1. Citez deux caractéristiques montrant que la qualité des images EPI est inférieure à cellede l’image anatomique. Vous pouvez par exemple comparer l’image anatomique aveccelle d'EPI et montrer la présence d’artefacts (préciser le type d’artefact). 3pts     **double click here to add your answer** L’utilité d’acquérir autant de volumes à la suite est de tester la présence d’une activité neuronalelorsqu’une tâche motrice, sensorielle ou cognitive est effectuée par le sujet pendant l’acquisition.Cette expérience s’appelle IRM fonctionnelle. La beauté de cette technique est qu’elle permetde localiser spatialement l’origine de l’activité neuronale. La précision de cette localisationdépend donc de la résolution spatiale des volumes EPI (ici, 4×4×6 mm^3) ainsi que du couplage neurovasculaire.    La façon de procéder est la suivante. Pendant l’acquisition des nombreux volumes, le sujet estsoumis à une activité fonctionnelle (passive ou active). On appelle cette période « ON ». Durantces périodes, l'activation des neurones suscite un afflux sanguin qui influence le signal IRMflocalement, dans la région activée du cerveau. Afin de pouvoir discriminer l’impact des périodesON sur les images, Il est important d’avoir aussi des périodes dites « OFF », pendant lesquellesle sujet est au repos et ne subit aucune activité contrôlée. La succession des périodes ON etOFF correspond au « paradigme » de l’expérience IRMf.     5.2. Comme mentionné plus haut, le paradigme IRMf est composé de N cycles "ON-OFF". La durée d'un cycle est de 90 secondes. Trouvez N.1pt<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>5.3. Extraire le décours temporel ( time course ) des voxels suivants :    [34,34,18]    [26,14,8]    [34,34,13]    [44,26,9]    [30,52,10]    [44,18,11]    Afficher les décours sur le même plot. Ne pas oublier les unités. Quel est le voxel oùl’activité neuronale semble avoir lieu ?2pts<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>Nous allons maintenant partir à la recherche de l’activité neuronale... Pour cela, nous souhaitons savoir de façon exhaustive où l’activité neuronale a eu lieu. Nous pourrions continuer la méthode d’identification comme réalisé en 5.2 pour tous les voxels du volume, mais cela reviendrait à identifier manuellement nx × ny × nz voxels, soit 86016 voxels !! Par ailleurs il serait souhaitable d’utiliser une approche davantage ​quantitative que celle utilisée précédemment, qui se basait sur notre jugement. Utilisons notre cerveau pour trouver une façon plus efficace d’étudier le cerveau !Une approche communément utilisée est de construire une carte statistique qui teste, pourchaque voxel, la correspondance temporelle entre le paradigme et le décours temporel.     Une façon de faire est de moyenner le signal pendant la période ON et pendant la période OFF, puisde faire la différence entre ces deux moyennes. Cette différence sera ensuite divisée par l’écarttype du signal. Cela revient à calculer le rapport contraste à bruit (CNR) de l’activité neuronalepour chaque voxel .<jupyter_code># On charge le fichier et on récupère les données images
nii_fmri = nib.load('fmri/fmri.nii.gz')
image_fmri = np.array(nii_fmri.dataobj)
# On moyenne sur la 4e dimension (le temps)
data_mean = np.mean(image_fmri, axis=3)
# On crée un nouvel objet nibabel
nii_mean = nib.Nifti1Image(data_mean, np.eye(4), header=nii_fmri.header)
# On sauvegarde en fichier NIfTI
nib.save(nii_mean, 'fmri/fmri_mean.nii')
nip.view_img(nii_mean, cut_coords=[32, 26, 12], title="fmri mean", cmap='gray', symmetric_cmap=False, bg_img=False, black_bg=True)<jupyter_output><empty_output><jupyter_text>5.4. Calculez une carte (valeur à chaque voxel) de CNR de l’activité neuronale et sauvegardez cette carte en fichier NIfTI.    3pts<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.
# Tips: Pour sauvegarder votre carte de CNR, utilisez: 
# >> nii_cnr = nib.Nifti1Image(abs(CNR_map), np.eye(4), header=nii_fmri.header)
# >> nib.save(nii_cnr, 'fmri/CNR_map.nii')<jupyter_output><empty_output><jupyter_text>5.5. Afficher la carte de CNR en superposition de l'EPI moyenne.    2pts<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.
# Tips: Pour afficher deux images en superposition, utilisez:
# >> nip.view_img(PATH_TO_FOREGROUND_IMAGE, threshold=1.5, cut_coords=[33, 33, 14], title="CNR overlaid on fMRI", cmap="OrRd", bg_img=PATH_TO_BACKGROUND_IMAGE, symmetric_cmap=False, black_bg=True)<jupyter_output><empty_output><jupyter_text>5.6. On peut considérer que les changements hémodynamiques induits par l’activité neuronale sont étalés sur plusieurs voxels voisins. Décrire une méthode permettant d’augmenter le CNR pour détecter l’activité neuronale (2 lignes max).    2pts         **double click here to add your answer** Le cortex est organisé en régions topologiques fonctionnelles, i.e., une zone corticale correspond à une fonction. Par exemple le lobe temporal situé en arrière du cerveau sera responsable de la mémoire, alors que le lobe pariétal sera responsable de l’activité motrice, etc. Historiquement, le «mapping» des fonctions corticales avait commencé avec <NAME>, au Montreal Neurological Institute. Alors qu’il étudiait des patients épileptiques avec des électrodes implantées, Dr. Penfield a pu identifier la localisation des aires somato-sensorielles. Dr. Brodmann a poursuivi ces travaux en proposant un atlas des fonctions du cerveau, encore utilisé aujourd’hui.     5.7. À partir de la carte statistique ci-dessous, retrouver le type de stimulation qui a été utilisé pour cette expérience d’IRMfonctionnelle. Pour cela, utilisez l’atlas interactif de Brodmann , qui relie aire corticale etfonction. Aucun code n’est nécessaire.     2pts             **double click here to add your answer** 5.8. Précédemment, nous avons utilisé une méthode temporelle pour identifier la localisation del’activité neuronale, i.e., basée sur la phase des transitions ON/OFF.Décrire une autre façon d’obtenir une carte de l’activité fonctionnelle, utilisant latransformée de Fourier.     1pt     **double click here to add your answer**  Partie IV : IRM de diffusion      6. Etudes d’images de diffusion Travaillez à présent dans le dossier diffusion/fantomes_fibres. Ce dossier comporte les 4données d’une acquisition pondérée en diffusion réalisée sur un fantôme synthétique. Le fantôme est décrit dans le fichier  ici.Les données ont été enregistrées dans le format NIFTI, dans le fichier dwi.nii.gz. Comme pour les images fMRI, il s’agit d’un volume 4D 96x48x1x65. La dimension est de 1 dans la direction Z car il s’agit d’une seule coupe axiale du fantôme. Nous avons 65 volumes dans la 4e dimension, qui ont été acquis avec différentes directions d’encodage de diffusion, i.e. direction de gradient de diffusion. L'information de direction des gradients de diffusion se trouve dans le fichier bvecs.txt.     6.1 Rappelez brièvement comment est encodée la diffusion en IRM.3pts     **double click here to add your answer** 6.2 Chargez et affichez le volume avec nifti_plotter() (voir code plus haut, dans la section fmri). Vous pouvez naviguer entre les différents volumes grâce au curseur “t” (correspondant à chaque ligne des bvecs). Certains volumes présentent beaucoup plus de signal que d'autres. Lesquels, et à quoi cela est-il dû ?2pts<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>**double click here to add your answer** 6.3 Affichez deux volumes sur une ligne (en utilisant subplot). À gauche: sans encodage de diffusion, à droite : avec un encodage dans la direction verticale. 2pts<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>Grâce aux nombreuses directions d'encodage de diffusion acquisent ici, on peut résoudre les 6 inconnues du tenseur de diffusion [D], voxel par voxel. Ce tenseur représente l’ellipsoïde de diffusion, et permet d’indiquer la direction des fibres du tissue dans ce voxel (voir cours) :  6.4 Les 65 directions $\vec{u}$ sont listées dans le fichier bvecs.txt (utilisez np.loadtxt('bvecs.txt')). Ecrivez un script permettant de trouver les 6 inconnues Dxx, Dyy, ... du tenseur de diffusion voxel par voxel.Tips: - Les lignes nulles de la matrice u correspondent aux images b=0 (i.e. pas d'encodage de diffusion).- Développez $\vec{u}^{T}.D.\vec{u}$ dans l'équation pour retrouver une équation linéaire de la forme : $y=H.d$, avec $d=[Dxx Dyy Dzz Dxy Dxz Dyz]^T$- Résoudre cette équation surdéterminée voxel par voxel (voir “pseudo-solution” surinternet)<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.<jupyter_output><empty_output><jupyter_text>Si vous n'avez pas pu faire la question précédente, nous avons résolu l’équation voxel par voxel. Les éléments du tenseur de diffusion ont été stocké dans le ficher DxxDyyDzzDxyDxzDyz.nii. Ce fichier a donc de 4 dimensions : 96x48x1x6. La 4e dimension correspond au 6 éléments du tenseurs $[Dxx, Dyy, Dzz, Dxy, Dxz, Dyz]$ (en $mm^2/s$).  6.5 Diagonalisez le tenseur de diffusion voxel par voxel pour trouver le vecteur de diffusion principal $\vec{v_p}$ , ainsi que le coefficient de diffusion dans cette direction $\vec{L_p}$ . Affichezune image montrant la direction des fibres pondéré par $\vec{L_p}$.2pts<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.
# 
# Tips:
# - np.linalg.eig sert à diagonaliser le tenseur et récupérer les valeurs et vecteurs propres.
# - np.diag(a) sert à créer une matrice diagonale avec le vecteur a comme valeur sur la diagonale.
# - np.multiply(a, b) est l'equivalent python de a.*b en matlab.
# - np.divide(a, b) est l'equivalent python de a./b en matlab
# - plt.quiver sert à tracer les direction. Voir documentation : https://matplotlib.org/api/_as_gen/matplotlib.pyplot.quiver.html.<jupyter_output><empty_output><jupyter_text>6.6. Interprétez l'image ainsi obtenue2pts         **double click here to add your answer** 6.7. A quoi correspondent les vecteurs propres et les valeurs propres associées?    1pt         **double click here to add your answer**     6.8. Appliquez votre script à la coupe axiale et coronale de    cerveau présent dans le dossier diffusion/brain. Ici, nous ne vous avons pas fourni$[Dxx, Dyy, Dzz, Dxy, Dxz, Dyz]$. Il vous faut donc :    - Normaliser cette nouvelle images par les images b=0.    - Calculer le vecteur $[Dxx, Dyy, Dzz, Dxy, Dxz, Dyz]$ à l'aide des équations    - Appliquer le script developpé a la question 6.5 sur ce nouveau vecteur.    3pts<jupyter_code># Ajoutez votre code ici. Commentez les lignes pertinentes.
# 
# Tips:
# - np.matmul()  permet d'effectuer une multiplication matricielle.
# - np.transpose()  permet d'obtenir la transposée d'une matrice.
# - np.linalg.pinv()  permet d'obtenir l'inverse d'une matrice non carrée en python avec numpy. 
# - np.log()  permet d'appliquer la fonction logaritmique à tout les éléments d'un vecteur.
# - np.squeeze()  est l'equivalent de la fonction squeeze en matlab.<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.06807977023583188, 'fraction_numerical': 0.014198454755066543, 'mean_word_length': 4.9642943305186975, 'pattern_counts': {'":': 0, '<': 102, '<?xml version=': 0, '>': 111, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '25', 'dir': 'jupyter-structured-clean-dedup', 'id': '456767', 'license': 'MIT', 'n_tokens_mistral': 8416, 'n_tokens_neox': 8045, 'n_words': 3244, 'path': 'lab3-irm/gbm8378-lab3-irm.ipynb', 'repo_name': 'gabesari-GBM/td', 'size': '24732'}