From 2ac4a8cb93713d49c5b1648bf2618e8a5fb5372c Mon Sep 17 00:00:00 2001 From: soazig Date: Sat, 12 Dec 2015 14:53:50 -0800 Subject: [PATCH 1/5] adding mask function and tests - still need work --- code/utils/functions/mask_functions.py | 64 ++++++++++++++++++++++++++ code/utils/tests/test_mask.py | 30 ++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 code/utils/functions/mask_functions.py create mode 100644 code/utils/tests/test_mask.py diff --git a/code/utils/functions/mask_functions.py b/code/utils/functions/mask_functions.py new file mode 100644 index 0000000..4458c0b --- /dev/null +++ b/code/utils/functions/mask_functions.py @@ -0,0 +1,64 @@ +"""mask_functions.py + +A collection of functions to make masks on data. +See test_* functions in this directory for nose tests +""" +from __future__ import print_function, division +import sys, os, pdb +import numpy as np +import nibabel as nib +from numpy.testing import assert_array_equal + +def make_mask_filtered_data(img_path, mask_path): + """Return the masked filtered data + + Parameters + ---------- + img_path: string + path to the 4D data + + mask_path: string + path to the mask function + + Return + ------ + masked_func: 4D array + masked filtered data + + """ + func_img = nib.load(img_path) + mask_img = nib.load(mask_path) + mask = mask_img.get_data() + func_data = func_img.get_data() + # Make data 4D to prepare for "broadcasting" + mask = np.reshape(mask, mask.shape + (1,)) + # "Broadcasting" expands the final length 1 dimension to match the func data + masked_func = nib.Nifti1Image(func_data, func_img.affine, func_img.header) + # nib.save(masked_func, 'masked_' + img_name ) + return masked_func + + +def apply_mask(data_3d, mask_3d): + """Apply mask on a 3D image and return the masked data + + Parameters + ---------- + data_3d: 3D numpy array + The subject's run image data + mask_3d: 3D numpy array + The mask for the corresponding data_3d + has 1 for the positions to select and + 0 for the positions to filter out. + Return + ------ + masked_func: 3D numpy array + masked data with the values + + """ + + a = data_3d.shape + b = mask_3d.shape + assert(a == b), "Data and mask shape differ \n" \ + + "Data shape is: %s\nMask shape is: %s" %(data_3d.shape, mask_3d.shape) + return arr_3d * mask_3d + diff --git a/code/utils/tests/test_mask.py b/code/utils/tests/test_mask.py new file mode 100644 index 0000000..e0a69a8 --- /dev/null +++ b/code/utils/tests/test_mask.py @@ -0,0 +1,30 @@ +"""test_mask.py +Tests for the functions in the mask_functions.py + +Run with: + nosetests test_mask.py +""" +import os, sys +import numpy as np +from numpy.testing import assert_array_equal + +#Append path to functions +sys.path.append(os.path.join(os.path.dirname(__file__), "../functions/")) +from mask_functions import * + + +def test_mask(): + # We make a 3D array of shape (3,3,2) + slab0 = np.reshape(np.arange(9), (3, 3)) + slab1 = np.reshape(np.arange(100, 109), (3, 3)) + arr_3d = np.zeros((2, 3, 3)) + arr_3d[0, :, :] = slab0 + arr_3d[1, :, :] = slab1 + # We make a mask as a 3D array of shape (2,3,3) + # with zeros on the 2nd component of the 1st dimension + mask_3d = np.zeros((2, 3, 3)) + mask_3d[0] = np.ones((3,3)) + # Defined the resulting masked array + masked_arr = np.zeros((2,3,3)) + masked_arr[0, :, :] = slab0 + assert_array_equal(apply_mask(arr_3d, mask_3d),masked_arr) From 2502e177dc9778acbc3c93998aae1436ff5d4f4a Mon Sep 17 00:00:00 2001 From: soazig Date: Sat, 12 Dec 2015 14:55:42 -0800 Subject: [PATCH 2/5] fixed mask_function.py --- code/utils/functions/mask_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/utils/functions/mask_functions.py b/code/utils/functions/mask_functions.py index 4458c0b..ea30d3e 100644 --- a/code/utils/functions/mask_functions.py +++ b/code/utils/functions/mask_functions.py @@ -60,5 +60,5 @@ def apply_mask(data_3d, mask_3d): b = mask_3d.shape assert(a == b), "Data and mask shape differ \n" \ + "Data shape is: %s\nMask shape is: %s" %(data_3d.shape, mask_3d.shape) - return arr_3d * mask_3d + return data_3d * mask_3d From 7653d177719ae33dad5cb54f05fa72d1ed95ce8f Mon Sep 17 00:00:00 2001 From: soazig Date: Sat, 12 Dec 2015 20:40:53 -0800 Subject: [PATCH 3/5] added function for the template --- code/utils/functions/mask_functions.py | 41 ++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/code/utils/functions/mask_functions.py b/code/utils/functions/mask_functions.py index ea30d3e..e6f8787 100644 --- a/code/utils/functions/mask_functions.py +++ b/code/utils/functions/mask_functions.py @@ -4,18 +4,24 @@ See test_* functions in this directory for nose tests """ from __future__ import print_function, division + import sys, os, pdb import numpy as np import nibabel as nib +import numpy.linalg as npl + +from os.path import splitext from numpy.testing import assert_array_equal +from scipy.ndimage import affine_transform -def make_mask_filtered_data(img_path, mask_path): + +def make_mask_filtered_data(func_path, mask_path): """Return the masked filtered data Parameters ---------- - img_path: string - path to the 4D data + func_path: string + path to the 4D data mask_path: string path to the mask function @@ -26,7 +32,7 @@ def make_mask_filtered_data(img_path, mask_path): masked filtered data """ - func_img = nib.load(img_path) + func_img = nib.load(func_path) mask_img = nib.load(mask_path) mask = mask_img.get_data() func_data = func_img.get_data() @@ -37,6 +43,31 @@ def make_mask_filtered_data(img_path, mask_path): # nib.save(masked_func, 'masked_' + img_name ) return masked_func +def resample_filtered_data(func_path, template_path): + """Resample template to filtered functional dataset + + Parameters + ---------- + func_path: string + path of the 4D filtered data to resample + template_path: string + path to the template to apply on the data + + """ + filtered_func = nib.load(func_path) + filtered_shape = filtered_func.shape[:3] + template_img = nib.load(mni_fname) + template_data = template_img.get_data() + vox2vox = npl.inv(template_img.affine).dot(filtered_func.affine) + M, trans = nib.affines.to_matvec(vox2vox) + resampled = affine_transform(template_data, M, trans, + output_shape=filtered_shape) + froot, ext = splitext(mni_fname) + new_name = froot + '_2mm' + ext + new_img = nib.Nifti1Image(resampled, filtered_func.affine, + template_img.header) + #nib.save(new_img, new_name) + return new_img def apply_mask(data_3d, mask_3d): """Apply mask on a 3D image and return the masked data @@ -48,7 +79,7 @@ def apply_mask(data_3d, mask_3d): mask_3d: 3D numpy array The mask for the corresponding data_3d has 1 for the positions to select and - 0 for the positions to filter out. + 0 for the positions to filter out. Return ------ masked_func: 3D numpy array From 893d9a412dd02a0bdcf2703181d8ad8ef076366e Mon Sep 17 00:00:00 2001 From: soazig Date: Sat, 12 Dec 2015 20:58:22 -0800 Subject: [PATCH 4/5] added a function t make a binary mask from a boolean mask --- code/utils/functions/mask_functions.py | 28 +++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/code/utils/functions/mask_functions.py b/code/utils/functions/mask_functions.py index ea30d3e..eb7799c 100644 --- a/code/utils/functions/mask_functions.py +++ b/code/utils/functions/mask_functions.py @@ -37,23 +37,37 @@ def make_mask_filtered_data(img_path, mask_path): # nib.save(masked_func, 'masked_' + img_name ) return masked_func +def make_binary_mask(data, mask_bool): + """Return a numpy array with 0 and 1 + Parameters + ---------- + + Return + ------ + + + """ + new_mask = np.zeros(data.shape) + new_mask[mask_bool] = 1 + return new_mask -def apply_mask(data_3d, mask_3d): - """Apply mask on a 3D image and return the masked data + +def apply_mask(data, mask): + """Apply mask on an image and return the masked data Parameters ---------- - data_3d: 3D numpy array + data: numpy array The subject's run image data - mask_3d: 3D numpy array + mask: numpy array same shape as data The mask for the corresponding data_3d has 1 for the positions to select and 0 for the positions to filter out. Return ------ - masked_func: 3D numpy array - masked data with the values - + masked_data: numpy array + Array with the values of the data at the selected positions + and 0 for the position filtered out by the mask. """ a = data_3d.shape From 675808b2207b734f755aa9f8e819e5c2cd7b1169 Mon Sep 17 00:00:00 2001 From: soazig Date: Sun, 13 Dec 2015 10:22:26 -0800 Subject: [PATCH 5/5] corrected mask function and tests --- code/utils/functions/mask_functions.py | 32 +++++++++++++++++++------- code/utils/tests/test_mask.py | 23 +++++++++++++++++- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/code/utils/functions/mask_functions.py b/code/utils/functions/mask_functions.py index 63ac135..57ccdf1 100644 --- a/code/utils/functions/mask_functions.py +++ b/code/utils/functions/mask_functions.py @@ -50,9 +50,18 @@ def make_binary_mask(data, mask_bool): Return ------ - - """ + data = np.asarray(data) + mask_bool = np.asarray(mask_bool) + assert(len(data.shape) == len(mask_bool.shape)),\ + "Data and mask shape differ \n" \ + + "Data dim is: %s\nMask dim is: %s" \ + %(len(data.shape), len(mask_bool.shape)) + assert(all(data.shape[i] >= mask_bool.shape[i] \ + for i in range(len(data.shape)))),\ + "Data and mask shape are not compatible"\ + +"Data shape is: %s\nMask shape is: %s"\ + %(data.shape, mask_bool.shape) new_mask = np.zeros(data.shape) new_mask[mask_bool] = 1 return new_mask @@ -101,10 +110,17 @@ def apply_mask(data, mask): Array with the values of the data at the selected positions and 0 for the position filtered out by the mask. """ + assert(data.shape == mask.shape), "Data and mask shape differ \n" \ + + "Data shape i: %s\nMask shape is: %s" %(data.shape, mask.shape) + return data * mask - a = data_3d.shape - b = mask_3d.shape - assert(a == b), "Data and mask shape differ \n" \ - + "Data shape is: %s\nMask shape is: %s" %(data_3d.shape, mask_3d.shape) - return data_3d * mask_3d - +if __name__=='__main__': + slab0 = np.reshape(np.arange(9), (3, 3)) + slab1 = np.reshape(np.arange(100, 109), (3, 3)) + arr_3d = np.zeros((2, 3, 3)) + arr_3d[0, :, :] = slab0 + arr_3d[1, :, :] = slab1 + arr_2d = np.arange(9).reshape((3,3)) + mask_bool2d = arr_2d < 10 + make_binary_mask(arr_3d,mask_bool2d) + pdb.set_trace() diff --git a/code/utils/tests/test_mask.py b/code/utils/tests/test_mask.py index e0a69a8..98b5452 100644 --- a/code/utils/tests/test_mask.py +++ b/code/utils/tests/test_mask.py @@ -4,6 +4,7 @@ Run with: nosetests test_mask.py """ +from __future__ import print_function import os, sys import numpy as np from numpy.testing import assert_array_equal @@ -13,7 +14,7 @@ from mask_functions import * -def test_mask(): +def test_apply_mask(): # We make a 3D array of shape (3,3,2) slab0 = np.reshape(np.arange(9), (3, 3)) slab1 = np.reshape(np.arange(100, 109), (3, 3)) @@ -28,3 +29,23 @@ def test_mask(): masked_arr = np.zeros((2,3,3)) masked_arr[0, :, :] = slab0 assert_array_equal(apply_mask(arr_3d, mask_3d),masked_arr) + + +def test_make_binary_mask(): + # We make a 3D array of shape (3,3,2) + slab0 = np.reshape(np.arange(9), (3, 3)) + slab1 = np.reshape(np.arange(100, 109), (3, 3)) + arr_3d = np.zeros((2, 3, 3)) + arr_3d[0, :, :] = slab0 + arr_3d[1, :, :] = slab1 + # We make a mask boolean as a 3D array of shape (2,3,3) + # that filtered the values below 100 + mask_bool = arr_3d < 100 + mask_3d = np.zeros((2, 3, 3)) + mask_3d[0] = np.ones((3,3)) + assert_array_equal(make_binary_mask(arr_3d,mask_bool), mask_3d) + arr_2d = np.arange(9).reshape((3,3)) + mask_bool2d = arr_2d < 10 +# make_binary_mask(arr_3d,mask_bool2d) + +