[PYTHON] Analyse de texture apprise avec la pyradiomique

pyradiomics

Vous pouvez calculer ces caractéristiques d'image.

Pour les images, valeur quantitative unidimensionnelle "premier ordre" ~~ (mais comprend également des fonctionnalités qui s'inquiètent de savoir si elle doit être interprétée comme unidimensionnelle) ~~, Forme qui analyse la forme, par exemple à quel point elle est ronde ou irrégulière et pixel C'est une bibliothèque qui peut analyser GLCM etc. pour examiner le modèle d'arrangement. Des parties telles que GLCM sont écrites en langage C pour accélérer, et en faisant référence à cela comme un objet Python, la vitesse de calcul est augmentée.

Prêt à l'emploi

Il a été créé par un chercheur, c'est donc très simple et vous pouvez rapidement le transformer en tableau CSV. Ici, je vais écrire jusqu'au point où le résultat du calcul est affiché.

environnement

Google colaboratory

procédure

Tout d'abord, installez temporairement la bibliothèque.

!pip install pyradiomics

Vous pouvez l'installer comme ça.

Collecting pyradiomics
  Downloading https://files.pythonhosted.org/packages/1d/6b/797d3fd59e16675f6d8fa3ad0f778a025e06bcb1fd595439d43aff0a522e/pyradiomics-2.2.0-cp36-cp36m-manylinux1_x86_64.whl (159kB)
     |████████████████████████████████| 163kB 2.8MB/s 
Collecting pykwalify>=1.6.0
  Downloading https://files.pythonhosted.org/packages/36/9f/612de8ca540bd24d604f544248c4c46e9db76f6ea5eb75fb4244da6ebbf0/pykwalify-1.7.0-py2.py3-none-any.whl (40kB)
     |████████████████████████████████| 40kB 5.4MB/s 
Requirement already satisfied: numpy>=1.9.2 in /usr/local/lib/python3.6/dist-packages (from pyradiomics) (1.17.3)
Collecting SimpleITK>=0.9.1
  Downloading https://files.pythonhosted.org/packages/bb/06/f3a67ef0e108d18840fd5e83f831d5ef1710ba46f05465fc50f9a505b518/SimpleITK-1.2.3-cp36-cp36m-manylinux1_x86_64.whl (42.5MB)
     |████████████████████████████████| 42.5MB 54kB/s 
Requirement already satisfied: six>=1.10.0 in /usr/local/lib/python3.6/dist-packages (from pyradiomics) (1.12.0)
Collecting PyWavelets<=1.0.0,>=0.4.0
  Downloading https://files.pythonhosted.org/packages/90/d0/09b2bf3368d5bba6ee1a8868ce94eebbb105fc8bf89fa43c90348b21a7cb/PyWavelets-1.0.0-cp36-cp36m-manylinux1_x86_64.whl (4.4MB)
     |████████████████████████████████| 4.4MB 35.8MB/s 
Requirement already satisfied: PyYAML>=3.11 in /usr/local/lib/python3.6/dist-packages (from pykwalify>=1.6.0->pyradiomics) (3.13)
Requirement already satisfied: docopt>=0.6.2 in /usr/local/lib/python3.6/dist-packages (from pykwalify>=1.6.0->pyradiomics) (0.6.2)
Requirement already satisfied: python-dateutil>=2.4.2 in /usr/local/lib/python3.6/dist-packages (from pykwalify>=1.6.0->pyradiomics) (2.6.1)
ERROR: albumentations 0.1.12 has requirement imgaug<0.2.7,>=0.2.5, but you'll have imgaug 0.2.9 which is incompatible.
Installing collected packages: pykwalify, SimpleITK, PyWavelets, pyradiomics
  Found existing installation: PyWavelets 1.1.1
    Uninstalling PyWavelets-1.1.1:
      Successfully uninstalled PyWavelets-1.1.1
Successfully installed PyWavelets-1.0.0 SimpleITK-1.2.3 pykwalify-1.7.0 pyradiomics-2.2.0

(Pour le moment, j'obtiens une erreur disant que vous devez utiliser la version inférieure d'imgaug, mais ignorez-la.)

Importez les fonctions requises.

import os  # needed navigate the system to get the input data
from radiomics import featureextractor  # This module is used for interaction with pyradiomics
import radiomics
from radiomics import firstorder, getTestCase, glcm, glrlm, glszm, imageoperations, shape, shape2D
import numpy as np
import six

#http://simpleitk.github.io/SimpleITK-Notebooks/01_Image_Basics.html
import SimpleITK as sitk
import matplotlib.pyplot as plt

Nous utiliserons les données de test fournies par pyradiomics. Le format d'image est l'image au format Nrrd qui est souvent utilisée dans la zone de traitement d'image 3D (3DSlicer). Vous pouvez utiliser la bibliothèque SimpleITK pour le chargement. Il peut prendre en charge différents formats d'image. Même si Nrrd n'est pas disponible, vous pouvez le remplacer par tiff ou png. (Si vous utilisez Dicom, vous pouvez utiliser pydicom pour le convertir en NDArray, puis le convertir en image ITK simple.) (https://github.com/Radiomics/pyradiomics/issues/339) Utilisons l'échantillon "lung2".

# brain1, brain2, breast1, lung1,lung2,(prostate_phantom)
# brain,1,2 peut avoir le mauvais masque (pas de zone d'étiquette)?
imageName, maskName = getTestCase('lung2')
image = sitk.ReadImage(imageName)
mask = sitk.ReadImage(maskName)

Si vous avez téléchargé une image dans un format commun (par exemple tif) sur votre note Colab, procédez comme suit:

#Appel depuis le fichier de colab (exemple en supposant qu'il se trouve dans le répertoire parent).
# imagePath = os.path.join(os.getcwd(), "lung2" + "_image.tif")
# maskPath = os.path.join(os.getcwd(), "lung2" + "_label.tif")
# image = sitk.ReadImage(imagePath)
# mask = sitk.ReadImage(maskPath)

Assurez-vous qu'il se charge correctement. (Le découpage peut être effectué ci-dessous, mais notez que la séquence de pixels est numpy.adarray (h, w) pour itkImage (w, y))

ndImg = sitk.GetArrayFromImage(image)
ndLbl = sitk.GetArrayFromImage(mask)
plt.imshow(ndImg[24])
plt.show()
plt.imshow(ndLbl[24])
plt.show()

ダウンロード.png ダウンロード (1).png

Ces données sont des données 3D. Parce que les images 2D sont alignées dans la direction de l'axe Z. Je pense personnellement que la pyradiomique est censée effectuer des calculs 3D depuis le début.

Créez un fichier de paramètres. C'est facile ici, mais ça marche par défaut.

settings = {}
settings['binWidth'] = 25
# If enabled, resample image (resampled image is automatically cropped.
settings['resampledPixelSpacing'] = None  # [3,3,3] is an example for defining resampling (voxels with size 3x3x3mm)
settings['interpolator'] = sitk.sitkBSpline
settings['label'] = 1 #Parce que la zone de masque a une valeur de pixel de 1 (sinon elle est de 0).

Recadrez la partie du masque. Ce sera un ensemble d'images 2D de la zone tumorale uniquement. (C'est un volume 3D.)

#Vérifiez l'intégrité du masque et créez une bbox# 2020/1/23 Addendum
bb, correctedMask = imageoperations.checkMask(image, mask)
if correctedMask is not None:
  mask = correctedMask
image, mask = imageoperations.cropToTumorMask(image, mask, bb)

La préparation est terminée. Exécutez ensuite le calcul.

Tout d'abord, calculez la quantité de caractéristiques unidimensionnelles à partir du volume rogné. Il génère également le type et la signification.

firstOrderFeatures = firstorder.RadiomicsFirstOrder(image, mask, **settings)
# firstOrderFeatures.enableFeatureByName('Mean', True)
firstOrderFeatures.enableAllFeatures()

print('Will calculate the following first order features: ')
for f in firstOrderFeatures.enabledFeatures.keys():
  print('  ', f)
  print(getattr(firstOrderFeatures, 'get%sFeatureValue' % f).__doc__)

print('Calculating first order features...')
results = firstOrderFeatures.execute()
print('done')

print('Calculated first order features: ')
for (key, val) in six.iteritems(results):
  print('  ', key, ':', val)

Viennent ensuite les caractéristiques de la forme.

shapeFeatures = shape.RadiomicsShape(image, mask, **settings)
shapeFeatures.enableAllFeatures()

print('Will calculate the following Shape features: ')
for f in shapeFeatures.enabledFeatures.keys():
  print('  ', f)
  print(getattr(shapeFeatures, 'get%sFeatureValue' % f).__doc__)

print('Calculating Shape features...')
results = shapeFeatures.execute()
print('done')

print('Calculated Shape features: ')
for (key, val) in six.iteritems(results):
  print('  ', key, ':', val)

À partir de là, nous calculerons des fonctionnalités telles que GLCM.

# Show GLCM features
glcmFeatures = glcm.RadiomicsGLCM(image, mask, **settings)
glcmFeatures.enableAllFeatures()

print('Will calculate the following GLCM features: ')
for f in glcmFeatures.enabledFeatures.keys():
  print('  ', f)
  print(getattr(glcmFeatures, 'get%sFeatureValue' % f).__doc__)

print('Calculating GLCM features...')
results = glcmFeatures.execute()
print('done')

print('Calculated GLCM features: ')
for (key, val) in six.iteritems(results):
  print('  ', key, ':', val)

# Show GLRLM features
glrlmFeatures = glrlm.RadiomicsGLRLM(image, mask, **settings)
glrlmFeatures.enableAllFeatures()

print('Will calculate the following GLRLM features: ')
for f in glrlmFeatures.enabledFeatures.keys():
  print('  ', f)
  print(getattr(glrlmFeatures, 'get%sFeatureValue' % f).__doc__)

print('Calculating GLRLM features...')
results = glrlmFeatures.execute()
print('done')

print('Calculated GLRLM features: ')
for (key, val) in six.iteritems(results):
  print('  ', key, ':', val)

# Show GLSZM features
glszmFeatures = glszm.RadiomicsGLSZM(image, mask, **settings)
glszmFeatures.enableAllFeatures()

print('Will calculate the following GLSZM features: ')
for f in glszmFeatures.enabledFeatures.keys():
  print('  ', f)
  print(getattr(glszmFeatures, 'get%sFeatureValue' % f).__doc__)

print('Calculating GLSZM features...')
results = glszmFeatures.execute()
print('done')

print('Calculated GLSZM features: ')
for (key, val) in six.iteritems(results):
  print('  ', key, ':', val)

#Je vais le faire ici.

Le processus ci-dessus peut également être une analyse 2D si vous entrez une image 2D en entrée, mais si vous savez qu'il s'agit d'une analyse 2D depuis le début, vous pouvez la saisir comme suit. Ne passez qu'une seule image.

# choose 2D array
#La mémoire est référencée et modifiée, alors appelez-la à nouveau.
imageName, maskName = getTestCase('lung2')
imageStack = sitk.ReadImage(imageName)
maskSatck = sitk.ReadImage(maskName)

#Extraire les pixels sous forme de matrice pour les calculs d'images paramétriques, etc.(Exemple pour la 24e tranche)
ndimage = sitk.GetArrayFromImage(imageStack)[24]
ndmask = sitk.GetArrayFromImage(maskStack)[24]

#Fondamentalement, les données qui étaient à l'origine une image DICOM ont une dimension de 3, elles sont donc développées.
ndimage = np.expand_dims(ndimage, axis=0)
ndmask = np.expand_dims(ndmask, axis=0)

print(ndimage.shape)# (1, 512, 512)Même avec force2D, la forme doit être en 3D.
print(ndmask.shape)# (1, 512, 512)

Si vous souhaitez réaffecter le pixel ndarray en tant qu'image sitk après avoir calculé pour diverses raisons, procédez comme suit.

image = sitk.GetImageFromArray(ndimage)
mask = sitk.GetImageFromArray(ndmask)

Réinitialisez les informations telles que la taille des pixels. (Ajouté le 14/11/2019, ajouté le 21/12)

# copy geometric/calibration info
image.CopyInformation(imageStack[:,:,24]) 
mask.CopyInformation(maskStack[:,:,24]) 

#Sinon, si l'image d'origine contient des métadonnées et qu'il n'y a pas de changement dans les informations géométriques telles que la taille de la matrice, l'origine, l'espacement des pixels, etc., copiez les métadonnées à partir des données d'origine.
#Cependant, dans le cas de DICOM (bien que cette fois ce soit tiff), il est préférable de mettre à jour les informations telles que l'UID de série et l'heure de création de l'image.

for i,key in enumerate(imageStack[:,:,24].GetMetaDataKeys()):
        image.SetMetaData(key, imageStack[:,:,24].GetMetaData(key))
for i,key in enumerate(maskStack[:,:,24].GetMetaDataKeys()):
        mask.SetMetaData(key, maskStack[:,:,24].GetMetaData(key))

Dans les paramètres, ajoutez force2D.

settings = {}
settings['binWidth'] = 25
# If enabled, resample image (resampled image is automatically cropped.
settings['resampledPixelSpacing'] = None  # [3,3,3] is an example for defining resampling (voxels with size 3x3x3mm)
settings['interpolator'] = sitk.sitkBSpline
settings['label'] = 1
settings['force2D'] = True
settings['correctMask'] = True #Si les informations géométriques telles que l'origine de l'image à analyser et l'image du masque sont différentes, elles seront ajustées automatiquement.

Le reste du processus est le même, donc seul le premier ordre est affiché ici.

# Show the first order feature calculations
firstOrderFeatures = firstorder.RadiomicsFirstOrder(image, mask, **settings)
# firstOrderFeatures.enableFeatureByName('Mean', True) #Lors de la spécification d'un élément spécifique
firstOrderFeatures.enableAllFeatures()

#Commentez parce que c'est un doublon.
# print('Will calculate the following first order features: ')
# for f in firstOrderFeatures.enabledFeatures.keys():
#   print('  ', f)
#   print(getattr(firstOrderFeatures, 'get%sFeatureValue' % f).__doc__)

print('Calculating first order features...')
results = firstOrderFeatures.execute()
print('done')

print('Calculated first order features: ')
for (key, val) in six.iteritems(results):
  print('  ', key, ':', val)

c'est tout.

VisionaryImagingServices, Inc. Tatsuaki Kobayashi

Reference

Recommended Posts

Analyse de texture apprise avec la pyradiomique
Analyse de données avec python 2
Analyse du panier avec Spark (1)
Analyse de dépendance avec CaboCha
Analyse vocale par python
Analyse vocale par python
Analyse dynamique par Valgrind
Effectuer une analyse de régression avec NumPy
Analyse de données avec Python
L'apprentissage automatique appris avec Pokemon
[Python] Analyse morphologique avec MeCab
[Analyse de co-occurrence] Analyse de co-occurrence facile avec Python! [Python]
Analyse de régression multiple avec Keras
Analyse de squelette planaire avec Python
Analyse morphologique japonaise avec Python
Analyse des secousses musculaires avec Python
[PowerShell] Analyse morphologique avec SudachiPy
Analyse des émotions par SMS avec ML-Ask
Analyse d'impédance (EIS) avec python [impedance.py]
[Python] Programmation orientée objet apprise avec Pokemon
Analyse des composants principaux avec Spark ML
Expérience d'apprentissage Perceptron apprise avec Python
Structure de données Python apprise avec la chimioinfomatique
Ramassage efficace du réseau avec Python
1. Statistiques apprises avec Python 1-1. Statistiques de base (Pandas)
Analyse pratique avec Pandas + notebook Jupyter
Service mesh appris avec Docker Swarm
J'ai joué avec Mecab (analyse morphologique)!
Optimisation apprise avec OR-Tools Part0 [Introduction]
Analyse de données à partir de python (visualisation de données 1)
Analyse de régression logistique Self-made avec python
Analyse de données à partir de python (visualisation de données 2)