/collageradiomics

Python Implementation of the CoLlAGe radiomics descriptor. CoLlAGe captures subtle anisotropic differences in disease pathologies by measuring entropy of co-occurrences of voxel-level gradient orientations on imaging computed within a local neighborhood.

Primary LanguagePythonBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

Continuous Delivery Documentation Status doi

Co-occurrence of Local Anisotropic Gradient Orientations (CoLlAGe)

Table of Contents

Science

Overview

Back to Table of Contents

CoLlAGe captures subtle anisotropic differences in disease pathologies by measuring entropy of co-occurrences of voxel-level gradient orientations on imaging computed within a local neighborhood.

CoLlAGe is based on the hypothesis that disruption in tissue microarchitecture can be quantified on imaging by measuring the disorder in voxel-wise gradient orientations. CoLlAGe involves assigning every image voxel a ‘disorder value’ associated with the co-occurrence matrix of gradient orientations computed around every voxel.

Details on extraction of CoLlAGe features are included in [1]. After feature extraction, the subsequent distribution or different statistics such as mean, median, variance etc can be computed and used in conjunction with a machine learning classifier to distinguish similar appearing pathologies. The feasibility of CoLlAGe in distinguishing cancer from treatment confounders/benign conditions and characterizing molecular subtypes of cancers has been demonstrated in the context of multiple challenging clinical problems.

Each of the 13 CoLlAGe correlate to one of the 13 Haralick texture features[2]:

  1. AngularSecondMoment
  2. Contrast
  3. Correlation
  4. SumOfSquareVariance
  5. SumAverage
  6. SumVariance
  7. SumEntropy
  8. Entropy
  9. DifferenceVariance
  10. DifferenceEntropy
  11. InformationMeasureOfCorrelation1
  12. InformationMeasureOfCorrelation2
  13. MaximalCorrelationCoefficient

References

Back to Table of Contents

If you make use of this implementation, please cite the following paper:

[1] Prasanna, P., Tiwari, P., & Madabhushi, A. (2016). "Co-occurrence of Local Anisotropic Gradient Orientations (CoLlAGe): A new radiomics descriptor. Scientific Reports", 6:37241.

[2] R. M. Haralick, K. Shanmugam and I. Dinstein, "Textural Features for Image Classification," in IEEE Transactions on Systems, Man, and Cybernetics, vol. SMC-3, no. 6, pp. 610-621, Nov. 1973, doi: 10.1109/TSMC.1973.4309314.

Code

Back to Table of Contents

We made the collage object idempotent Our CoLlAGe module includes parameter tuning information in the output. It contains the image(s) and mask(s), and the settings applied upon them. This allows multiple fully reproducible runs without having to remember or find the original parameters.

Documentation can be found at http://collageradiomics.rtfd.io/

We depend on the following libraries:

  • matplotlib
  • numpy
  • scikit-learn
  • scikit-build
  • mahotas
  • scipy

Installation & Setup

Back to Table of Contents

Pip Usage

pip3 install --upgrade collageradiomics

python3 -c 'import collageradiomics; print(collageradiomics.__name__)'

Local usage

# get the code
git clone https://github.com/radxtools/collageradiomics
cd collageradiomics

# set up virtual environment
python3 -m venv collageenv
source collageenv/bin/activate

# install requirements
sudo apt -y install build-essential gcc gfortran python-dev libopenblas-dev liblapack-dev cython libjpeg-dev zlib1g-dev
pip3 install -r requirements.txt

# run test script
cd modules
python3 test_script.py

Docker Sandbox

Back to Table of Contents

This is the most straightforward way to start playing with the code. And it does not require the git commands that the Jupyter examples require. This is simply a pre-built container that lets you start trying out the module in Python immediately.

sudo docker pull radxtools/collageradiomics-pip:latest
sudo docker run -it -v $PWD:/root radxtools/collageradiomics-pip

If your terminal prompt changes to root@[random_string]:/# then you are now working inside the standardized Docker sandbox container environment.

Then you can try to import collage:

python3 -c 'import collageradiomics; print(collageradiomics.__name__)'

Docker Notebooks

Prepare Jupyter Notebooks

To load the example jupyter notebooks, run the following commands (with or without sudo depending on your environment):

sudo docker pull radxtools/collageradiomics-pip:latest
sudo docker run -it radxtools/collageradiomics-pip

git clone https://github.com/radxtools/collageradiomics.git
sudo docker pull radxtools/collageradiomics-examples:latest
sudo docker run -it -p 8888:8888 -v $PWD:/root radxtools/collageradiomics-examples

Exploring The Examples

Back to Table of Contents

  1. Open up a web browser to http://localhost:8888
    Jupyter Home
  2. Navigate to the Jupyter ➡️ Examples directory.
    Jupyter Examples
  3. Click on one of the example *.ipynb files.
  4. Run Cell ➡️ Run all.
    Jupyter Run Cells Jupyter Output
  5. Feel free to add your own cells and run them to get familiar with the CoLlAGe code.
  6. To stop the Jupyter notebook and exit the Docker image, press Ctrl+C twice:

To run python code with collage:

root@12b12d2bff59:/# python
Python 3.8.2 (default, Apr 27 2020, 15:53:34) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import collageradiomics
>>> collageradiomics.__name__
'collageradiomics'

Python Usage

Back to Table of Contents

##################################################
# imports
import collageradiomics
import pydicom
import logging
from pydicom.pixel_data_handlers.util import apply_modality_lut, apply_voi_lut
from skimage.exposure import equalize_hist
import numpy as np
from sklearn.preprocessing import minmax_scale
from random import randint
##################################################


##################################################
# logging
level = logging.INFO
logging.basicConfig(level=level)
logger = logging.getLogger()
logger.setLevel(level)
logger.info('Hello, world.')
##################################################


##################################################
# loading data
local_dcm_file = 'test.dcm'
instance = pydicom.dcmread(local_dcm_file)
slice_instance_uid = instance.SOPInstanceUID
logger.debug(f'slice_instance_uid  = {slice_instance_uid}')
##################################################


##################################################
# preprocessing
logger.info('Correcting image...')
np_array = instance.pixel_array
corrected = apply_modality_lut(np_array, instance)
corrected = apply_voi_lut(corrected, instance)
scaled_array = equalize_hist(corrected)
logger.debug(f'np.histogram(scaled_array) = {np.histogram(scaled_array)}')
logger.info('done.')
##################################################


##################################################
# rectangular selection
width = 50
height = 50
min_row = randint(30,300)
max_row = min_row + height
min_col = randint(30,300)
max_col = min_col + width

original_shape = np_array.shape
logger.debug(f'original_shape = {original_shape}')
logger.info('Calculating collage features...')
mask_array = np.zeros(original_shape, dtype='int')
mask_array[min_row:max_row, min_col:max_col] = 1
##################################################


##################################################
# run collage
textures = collageradiomics.Collage(scaled_array, mask_array).execute()

logger.debug(f'textures.shape = {textures.shape}')
logger.debug(f'textures.dtype = {textures.dtype}')
logger.debug(f'np.histogram(textures.flatten()) = {np.histogram(textures.flatten(), range=(np.nanmin(textures), np.nanmax(textures)))}')
##################################################