Skip to content

Commit

Permalink
updated version with batch labels (useful for NIFTI) and updated NIFT…
Browse files Browse the repository at this point in the history
…I utils
  • Loading branch information
Ray Pomponio authored and Ray Pomponio committed Aug 6, 2020
1 parent c14546e commit 9857828
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 32 deletions.
4 changes: 3 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ achieved with an external model, or by using the argument* `return_s_data`
Installation
------------

Latest version: ``0.3.2`` (July 2020)
Latest version: ``0.3.3`` (August 2020)

Requirements:

Expand Down Expand Up @@ -186,6 +186,8 @@ Working with NIFTI Images

*This feature is currently in development.*

>>> from neuroHarmonize.harmonizationNIFTI import create_NIFTI_mask, flatten_NIFTIs

Visualize Fits of EB Priors
---------------------------

Expand Down
2 changes: 1 addition & 1 deletion neuroHarmonize/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .harmonizationLearn import harmonizationLearn, saveHarmonizationModel
from .harmonizationApply import harmonizationApply, harmonizationApplyNIFTI, loadHarmonizationModel
#from .utils import loadNIFTI
#from .harmonizationNIFTI.py import create_NIFTI_mask, flatten_NIFTIs
1 change: 1 addition & 0 deletions neuroHarmonize/harmonizationLearn.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def harmonizationLearn(data, covars, eb=True, smooth_terms=[],
# create dictionary that stores batch info
(batch_levels, sample_per_batch) = np.unique(covars[:,batch_col],return_counts=True)
info_dict = {
'batch_labels': batch_levels,
'batch_levels': batch_levels.astype('int'),
'n_batch': len(batch_levels),
'n_sample': int(covars.shape[0]),
Expand Down
76 changes: 47 additions & 29 deletions neuroHarmonize/harmonizationNIFTI.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,50 @@
import numpy as np
import pandas as pd

def create_NIFTI_mask(file_paths, threshold=0.0, output_path='thresholded_mask.nii.gz'):
# define function to make mask based on list of image paths
def create_NIFTI_mask(paths, threshold=0.0, output_path='thresholded_mask.nii.gz'):
"""
Utility function for loading multiple NIFTI images and vectorizing for
harmonization. All images must have the same dimensions and orientation.
Creates a binary mask from a list of NIFTI images. Image intensities will be
averaged, then thresholded across the entire dataset. Result will have the
same affine matrix as the first image in the dataset.
Arguments
---------
file_paths : a pandas DataFrame
list of file paths (absolute or relative) for each NIFTI image
must contain a single column "PATH" with file paths
paths : a pandas DataFrame
must contain a single column "PATH" with file paths to NIFTIs
dimensions must be identical for all images
threshold : float, default 1.0
determines the threshold value below which voxel intensities will be
masked, or excluded
images in file_paths are averaged and a mask is created for all voxels
with average intensities > threshold
threshold : a float, default 0.0
the threshold at which to binarize the mask
average intensity must be greater than threshold to be included in mask
output_path : str, default "thresholded_mask.nii.gz"
desired output path for the image mask
the output file path, must include extension (.nii.gz)
Returns
-------
nifti_avg : a numpy array
average image intensities, dimensions are same as input images
array of average image intensities
dimensions are identical to images in `paths`
nifti_mask : a numpy array
mask of voxels included in data_array
dimensions are same as input images
1=included, 0=excluded/masked
array of binarized mask (1=include, 0=exclude)
dimensions are identical to images in `paths`
affine : a numpy array
affine matrix used to save mask
"""
# count number of images
n_images = file_paths.shape[0]
n_images = paths.shape[0]
# begin summing image intensities
i = 0
nifti_i = nib.load(file_paths.PATH[i])
nifti_i = nib.load(paths.PATH[i])
affine_0 = nifti_i.affine
nifti_sum = nifti_i.get_fdata()
# iterate over all images
for i in range(0, n_images):
nifti_i = nib.load(file_paths.PATH[i])
nifti_i = nib.load(paths.PATH[i])
nifti_sum += nifti_i.get_fdata()
if (i==500):
print('PROGRESS: loaded %d of %d images...' % (i, n_images))
Expand All @@ -53,32 +57,46 @@ def create_NIFTI_mask(file_paths, threshold=0.0, output_path='thresholded_mask.n
# create mask and save as NIFTI image
nifti_mask = nifti_avg.copy()
nifti_mask[nifti_mask>0.0] = 1.0
img = nib.Nifti1Image(nifti_mask, np.eye(4))
img = nib.Nifti1Image(nifti_mask, affine_0)
img.to_filename(output_path)
return nifti_avg, nifti_mask
return nifti_avg, nifti_mask, affine_0

def flatten_NIFTIs(file_paths, mask_path, output_path='flattened_nifti_array.npy'):
# define function to flatten images and store array
def flatten_NIFTIs(paths, mask_path, output_path='flattened_NIFTI_array.npy'):
"""
mask must be created with create_NIFTI_mask()
Flattens a dataset of NIFTI images to a 2D array.
Arguments
---------
file_paths : a pandas DataFrame
list of file paths (absolute or relative) for each NIFTI image
must contain a single column "PATH" with file paths
paths : a pandas DataFrame
must contain a single column "PATH" with file paths to NIFTIs
dimensions must be identical for all images
mask_path : a str
file path to the mask, must be created with `create_NIFTI_mask`
output_path : a str, default "flattened_NIFTI_array.npy"
Returns
-------
nifti_array : a numpy array
array of flattened image intensities
dimensions are N_Images x N_Masked_Voxels
"""
print('\nWARNING: this procedure will consume large amounts of memory.')
print(' Consider down-sampling, masking aggressively, and/or sub-sampling NIFTIs...')
# load mask (1=GM tissue, 0=Non-GM)
nifti_mask = (nib.load(mask_path).get_fdata().astype(int)==1)
n_voxels_flattened = np.sum(nifti_mask)
# count images
n_images = file_paths.shape[0]
n_images = paths.shape[0]
# initialize empty container
nifti_array = np.zeros((n_images, n_voxels_flattened))
# iterate over images and fill container
print('Flattening %d NIFTI images with %d voxels...' % (n_images, n_voxels_flattened))
for i in range(0, n_images):
nifti_i = nib.load(file_paths.PATH[i]).get_fdata()
nifti_i = nib.load(paths.PATH[i]).get_fdata()
nifti_array[i, :] = nifti_i[nifti_mask]
if (i==500):
print('PROGRESS: loaded %d of %d images...' % (i, n_images))
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ def readme():
return f.read()

setup(name='neuroHarmonize',
version='0.3.2',
version='0.3.3',
description='Harmonization tools for multi-center neuroimaging studies.',
long_description=readme(),
url='https://github.com/rpomponio/neuroHarmonize',
Expand Down

0 comments on commit 9857828

Please sign in to comment.