Hi Bissenbay,
It’s not really clear what your inputs and outputs are, here, but I’m going to assume that you always have/want NIfTI-1 files. So let’s say you have:
-
T1w.nii.gz
- your structural image
-
lesion_mask.nii.gz
- an image that is 1 where the lesion is and 0 elsewhere
And what you want is:
-
eroded_mask.nii.gz
- A mask where a voxel is 1 iff it and all of its neighbors are 1 in lesion_mask.nii.gz
-
isolated_voxels.nii.gz
- A mask where a voxel is 1 iff it and none of its neighbors are 1 in lesion_mask.nii.gz
-
cleaned_mask.nii.gz
- The xor
of lesion_mask.nii.gz
and isolated_voxels.nii.gz
So you should be able to do this all with nibabel and numpy.
import nibabel as nb
import numpy as np
Now from what I can tell, there’s no actual need to work with the structural image, so we’ll work with the lesion_mask.nii.gz
:
orig_mask = nb.load('lesion_mask.nii.gz')
data = orig_mask.get_data()
Now, you said that you had 'L'
instead of 1 to indicate the mask, so I’m not really sure what data you’re actually working with, but you can get to a binary mask from a numpy
array of strings like so:
data = np.array(data == 'L', dtype=np.uint8)
In any event, your data ought to be binary:
assert np.array_equal(np.unique(data), [0, 1])
From here, you can now use all of the tools of scipy.ndimage
on your array to perform erosion, and identify isolated voxels. One function you might find useful is scipy.ndimage.interpolation.shift
, if you need to manually make copies of your array that are shifted.
Suppose that we’ve now created new data arrays that fit your requirements. You’ll want to create new NIfTI images out of those data arrays. To keep things in the same space, we’ll keep the original affine and header:
eroded_img = nb.Nifti1Image(eroded_data, affine=orig_mask.affine,
header=orig_mask.header)
Because we’re using binary images, to be safe, let’s set the on-disk data type to a single byte:
eroded_img.set_data_dtype(np.uint8)
Then we can save the image:
eroded_img.to_filename('eroded_mask.nii.gz')
I’ve made some assumptions, such as you’re using NIfTI-1 images… you can do basically the same with NIfTI-2, just making the obvious change to Nifti2Image
. (More generally, you can let nibabel do the work for you by invoking orig_mask.__class__(data, array, header)
, but that’s mild Python magic, so if it’s not clear what’s going on there, you can ignore this comment.)
Hopefully this can get you started. There are definitely a lot of holes to fill in, so feel free to ask for further guidance.