def test_n4_bias_field_correction(self): #def n4_bias_field_correction(image, mask=None, shrink_factor=4, # convergence={'iters':[50,50,50,50], 'tol':1e-07}, # spline_param=200, verbose=False, weight_mask=None): for img in self.imgs: image_n4 = ants.n4_bias_field_correction(img) mask = img > img.mean() image_n4 = ants.n4_bias_field_correction(img, mask=mask)
def process(filename: str) -> str: img = ants.image_read(filename) img = ants.n4_bias_field_correction( img, shrink_factor=options.shrink_factor, convergence=conv) output = path.join(options.outputdir, path.basename(filename)) img.to_file(output) logger.info(output) return output
def bias_field_correction(image): #image : ants format image from time import time import ants t1 = time() jk_corrected = ants.n4_bias_field_correction(image) t2 = time() print("Time taken for N4 bias field correction: ", t2 - t1) return jk_corrected
def n4_correction_ants(im_input): image = ants.image_read(im_input, 3) image_target = im_input.replace('.nii.gz', '_corrected.nii.gz') image_result: ANTsImage = ants.n4_bias_field_correction(image, shrink_factor=3, convergence={'iters': [50, 50, 30, 20], 'tol': 1e-07}, spline_param=300, verbose=False) image_result.to_file(image_target) print(f"Saved image: ${image_target}")
def test_n4_bias_field_correction_example(self): image = ants.image_read(ants.get_ants_data('r16')) image_n4 = ants.n4_bias_field_correction(image) # spline param list image_n4 = ants.n4_bias_field_correction(image, spline_param=(10, 10)) # image not float image_ui = image.clone('unsigned int') image_n4 = ants.n4_bias_field_correction(image_ui) # weight mask mask = image > image.mean() ants.n4_bias_field_correction(image, weight_mask=mask) # len(spline_param) != img.dimension with self.assertRaises(Exception): ants.n4_bias_field_correction(image, spline_param=(10, 10, 10)) # weight mask not ANTsImage with self.assertRaises(Exception): ants.n4_bias_field_correction(image, weight_mask=0.4)
def preprocess_single_subject(image, seg_image): """ Takes a T1 and its segmentation, processes them, and returns the processed images This is really the only thing that needs to be changed according to the user's preferences for preprocessing """ #image_mask = ants.get_mask(image) # run N4 bias correction image = ants.n4_bias_field_correction(image) #, mask=image_mask) # downsample to 2mm^3 resolution image = image.resample_image((2, 2, 2), interp_type=0) seg_image = seg_image.resample_image((2, 2, 2), interp_type=1) return image, seg_image
def bias_field_correction(path: str, extension: str = '.nii.gz'): """ This ROI generator follows the structure FILE/FILE+extension and generates a ROI file with the name FILE/FILE+_norm+extension Parameters ---------- path Images Path Returns Generated ROI images ------- """ for scan_id in os.listdir(path): print('Bias Field correction : ', scan_id) image = ants.image_read( os.path.join(path, scan_id, scan_id + extension)) image_n4 = ants.n4_bias_field_correction(image) ants.image_write(image_n4, os.path.join(path, scan_id, scan_id + extension)) return
def preprocess_brain_image(image, truncate_intensity=(0.01, 0.99), brain_extraction_modality=None, template_transform_type=None, template="biobank", do_bias_correction=True, return_bias_field=False, do_denoising=True, intensity_matching_type=None, reference_image=None, intensity_normalization_type=None, antsxnet_cache_directory=None, verbose=True): """ Basic preprocessing pipeline for T1-weighted brain MRI Standard preprocessing steps that have been previously described in various papers including the cortical thickness pipeline: https://www.ncbi.nlm.nih.gov/pubmed/24879923 Arguments --------- image : ANTsImage input image truncate_intensity : 2-length tuple Defines the quantile threshold for truncating the image intensity brain_extraction_modality : string or None Perform brain extraction using antspynet tools. One of "t1", "t1v0", "t1nobrainer", "t1combined", "flair", "t2", "bold", "fa", "t1infant", "t2infant", or None. template_transform_type : string See details in help for ants.registration. Typically "Rigid" or "Affine". template : ANTs image (not skull-stripped) Alternatively, one can specify the default "biobank" or "croppedMni152" to download and use premade templates. do_bias_correction : boolean Perform N4 bias field correction. return_bias_field : boolean If True, return bias field as an additional output *without* bias correcting the preprocessed image. do_denoising : boolean Perform non-local means denoising. intensity_matching_type : string Either "regression" or "histogram". Only is performed if reference_image is not None. reference_image : ANTs image Reference image for intensity matching. intensity_normalization_type : string Either rescale the intensities to [0,1] (i.e., "01") or zero-mean, unit variance (i.e., "0mean"). If None normalization is not performed. antsxnet_cache_directory : string Destination directory for storing the downloaded template and model weights. Since these can be resused, if is None, these data will be downloaded to a ~/.keras/ANTsXNet/. verbose : boolean Print progress to the screen. Returns ------- Dictionary with preprocessing information ANTs image (i.e., source_image) matched to the (reference_image). Example ------- >>> import ants >>> image = ants.image_read(ants.get_ants_data('r16')) >>> preprocessed_image = preprocess_brain_image(image, do_brain_extraction=False) """ from ..utilities import brain_extraction from ..utilities import regression_match_image from ..utilities import get_antsxnet_data preprocessed_image = ants.image_clone(image) if antsxnet_cache_directory == None: antsxnet_cache_directory = "ANTsXNet" # Truncate intensity if truncate_intensity is not None: quantiles = (image.quantile(truncate_intensity[0]), image.quantile(truncate_intensity[1])) if verbose == True: print("Preprocessing: truncate intensities ( low =", quantiles[0], ", high =", quantiles[1], ").") preprocessed_image[image < quantiles[0]] = quantiles[0] preprocessed_image[image > quantiles[1]] = quantiles[1] # Brain extraction mask = None if brain_extraction_modality is not None: if verbose == True: print("Preprocessing: brain extraction.") probability_mask = brain_extraction(preprocessed_image, modality=brain_extraction_modality, antsxnet_cache_directory=antsxnet_cache_directory, verbose=verbose) mask = ants.threshold_image(probability_mask, 0.5, 1, 1, 0) mask = ants.morphology(mask,"close",6).iMath_fill_holes() # Template normalization transforms = None if template_transform_type is not None: template_image = None if isinstance(template, str): template_file_name_path = get_antsxnet_data(template, antsxnet_cache_directory=antsxnet_cache_directory) template_image = ants.image_read(template_file_name_path) else: template_image = template if mask is None: registration = ants.registration(fixed=template_image, moving=preprocessed_image, type_of_transform=template_transform_type, verbose=verbose) preprocessed_image = registration['warpedmovout'] transforms = dict(fwdtransforms=registration['fwdtransforms'], invtransforms=registration['invtransforms']) else: template_probability_mask = brain_extraction(template_image, modality=brain_extraction_modality, antsxnet_cache_directory=antsxnet_cache_directory, verbose=verbose) template_mask = ants.threshold_image(template_probability_mask, 0.5, 1, 1, 0) template_brain_image = template_mask * template_image preprocessed_brain_image = preprocessed_image * mask registration = ants.registration(fixed=template_brain_image, moving=preprocessed_brain_image, type_of_transform=template_transform_type, verbose=verbose) transforms = dict(fwdtransforms=registration['fwdtransforms'], invtransforms=registration['invtransforms']) preprocessed_image = ants.apply_transforms(fixed = template_image, moving = preprocessed_image, transformlist=registration['fwdtransforms'], interpolator="linear", verbose=verbose) mask = ants.apply_transforms(fixed = template_image, moving = mask, transformlist=registration['fwdtransforms'], interpolator="genericLabel", verbose=verbose) # Do bias correction bias_field = None if do_bias_correction == True: if verbose == True: print("Preprocessing: brain correction.") n4_output = None if mask is None: n4_output = ants.n4_bias_field_correction(preprocessed_image, shrink_factor=4, return_bias_field=return_bias_field, verbose=verbose) else: n4_output = ants.n4_bias_field_correction(preprocessed_image, mask, shrink_factor=4, return_bias_field=return_bias_field, verbose=verbose) if return_bias_field == True: bias_field = n4_output else: preprocessed_image = n4_output # Denoising if do_denoising == True: if verbose == True: print("Preprocessing: denoising.") if mask is None: preprocessed_image = ants.denoise_image(preprocessed_image, shrink_factor=1) else: preprocessed_image = ants.denoise_image(preprocessed_image, mask, shrink_factor=1) # Image matching if reference_image is not None and intensity_matching_type is not None: if verbose == True: print("Preprocessing: intensity matching.") if intensity_matching_type == "regression": preprocessed_image = regression_match_image(preprocessed_image, reference_image) elif intensity_matching_type == "histogram": preprocessed_image = ants.histogram_match_image(preprocessed_image, reference_image) else: raise ValueError("Unrecognized intensity_matching_type.") # Intensity normalization if intensity_normalization_type is not None: if verbose == True: print("Preprocessing: intensity normalization.") if intensity_normalization_type == "01": preprocessed_image = (preprocessed_image - preprocessed_image.min())/(preprocessed_image.max() - preprocessed_image.min()) elif intensity_normalization_type == "0mean": preprocessed_image = (preprocessed_image - preprocessed_image.mean())/preprocessed_image.std() else: raise ValueError("Unrecognized intensity_normalization_type.") return_dict = {'preprocessed_image' : preprocessed_image} if mask is not None: return_dict['brain_mask'] = mask if bias_field is not None: return_dict['bias_field'] = bias_field if transforms is not None: return_dict['template_transforms'] = transforms return(return_dict)
def preprocess(img_path, out_dir, mask_path=None, res=(1, 1, 1), orientation='RAI', n4_opts=None): """ preprocess.py MR images according to a simple scheme, that is: 1) N4 bias field correction 2) resample to 1mm x 1mm x 1mm 3) reorient images to RAI Args: img_dir (str): path to directory containing images out_dir (str): path to directory for output preprocessed files mask_dir (str): path to directory containing masks res (tuple): resolution for resampling (default: (1,1,1) in mm n4_opts (dict): n4 processing options (default: None) Returns: None, outputs preprocessed images to file in given out_dir """ if n4_opts is None: n4_opts = {'iters': [200, 200, 200, 200], 'tol': 0.0005} logger.debug('N4 Options are: {}'.format(n4_opts)) # get and check the images and masks img_fns = img_path mask_fns = mask_path # create the output directory structure out_img_dir = os.path.join(out_dir, 'imgs') out_mask_dir = os.path.join(out_dir, 'masks') if not os.path.exists(out_dir): logger.info('Making output directory structure: {}'.format(out_dir)) os.mkdir(out_dir) if not os.path.exists(out_img_dir): logger.info('Making image output directory: {}'.format(out_img_dir)) os.mkdir(out_img_dir) if not os.path.exists(out_mask_dir) and mask_path is not None: logger.info('Making mask output directory: {}'.format(out_mask_dir)) os.mkdir(out_mask_dir) # preprocess the images by n4 correction, resampling, and reorientation _, img_base, img_ext = split_filename(img_fns) #logger.info('Preprocessing image: {} ({:d}/{:d})'.format(img_base, i, len(img_fns))) img = ants.image_read(img_fns) if mask_path is not None: _, mask_base, mask_ext = split_filename(mask_fns) mask = ants.image_read(mask_fns) smoothed_mask = ants.smooth_image(mask, 1) # this should be a second n4 after an initial n4 (and coregistration), once masks are obtained img = ants.n4_bias_field_correction(img, convergence=n4_opts, weight_mask=smoothed_mask) out_mask = os.path.join(out_mask_dir, mask_base + mask_ext) ants.image_write(mask, out_mask) else: img = ants.n4_bias_field_correction(img, convergence=n4_opts) if hasattr(img, 'reorient_image2'): img = img.reorient_image2(orientation) else: logger.info( 'Cannot reorient image to a custom orientation. Update ANTsPy to a version >= 0.1.5.' ) img = img.reorient_image((1, 0, 0))['reoimage'] out_img = os.path.join(out_img_dir, img_base + img_ext) ants.image_write(img, out_img)
def preprocess(img_dir, out_dir, mask_dir=None, res=(1., 1., 1.), orientation='RAI', n4_opts=None): """ preprocess.py MR images according to a simple scheme, that is: 1) N4 bias field correction 2) resample to x mm x y mm x z mm 3) reorient images to RAI Args: img_dir (str): path to directory containing images out_dir (str): path to directory for output preprocessed files mask_dir (str): path to directory containing masks res (tuple): resolution for resampling (default: (1,1,1) in mm) n4_opts (dict): n4 processing options. See ANTsPy for details. (default: None) Returns: None, outputs preprocessed images to file in given out_dir """ if n4_opts is None: n4_opts = {'iters': [200, 200, 200, 200], 'tol': 0.0005} logger.debug('N4 Options are: {}'.format(n4_opts)) # get and check the images and masks img_fns = glob_nii(img_dir) mask_fns = glob_nii( mask_dir) if mask_dir is not None else [None] * len(img_fns) assert len(img_fns) == len(mask_fns), 'Number of images and masks must be equal ({:d} != {:d})' \ .format(len(img_fns), len(mask_fns)) # create the output directory structure out_img_dir = os.path.join(out_dir, 'imgs') out_mask_dir = os.path.join(out_dir, 'masks') if not os.path.exists(out_dir): logger.info('Making output directory structure: {}'.format(out_dir)) os.mkdir(out_dir) if not os.path.exists(out_img_dir): logger.info('Making image output directory: {}'.format(out_img_dir)) os.mkdir(out_img_dir) if not os.path.exists(out_mask_dir) and mask_dir is not None: logger.info('Making mask output directory: {}'.format(out_mask_dir)) os.mkdir(out_mask_dir) # preprocess the images by n4 correction, resampling, and reorientation for i, (img_fn, mask_fn) in enumerate(zip(img_fns, mask_fns), 1): _, img_base, img_ext = split_filename(img_fn) logger.info('Preprocessing image: {} ({:d}/{:d})'.format( img_base, i, len(img_fns))) img = ants.image_read(img_fn) if mask_dir is not None: _, mask_base, mask_ext = split_filename(mask_fn) mask = ants.image_read(mask_fn) smoothed_mask = ants.smooth_image(mask, 1) # this should be a second n4 after an initial n4 (and coregistration), once masks are obtained img = ants.n4_bias_field_correction(img, convergence=n4_opts, weight_mask=smoothed_mask) if res is not None: if res != img.spacing: mask = ants.resample_image(mask, res, False, 1) mask = mask.reorient_image2(orientation) if hasattr(img, 'reorient_image2') else \ mask.reorient_image((1, 0, 0))['reoimage'] out_mask = os.path.join(out_mask_dir, mask_base + mask_ext) ants.image_write(mask, out_mask) else: img = ants.n4_bias_field_correction(img, convergence=n4_opts) if res is not None: if res != img.spacing: img = ants.resample_image(img, res, False, 4) if hasattr(img, 'reorient_image2'): img = img.reorient_image2(orientation) else: logger.info( 'Cannot reorient image to a custom orientation. Update ANTsPy to a version >= 0.1.5.' ) img = img.reorient_image((1, 0, 0))['reoimage'] logger.info('Writing preprocessed image: {} ({:d}/{:d})'.format( img_base, i, len(img_fns))) out_img = os.path.join(out_img_dir, img_base + img_ext) ants.image_write(img, out_img)
def __init__(self, ants_image=[[0.0]], **options): import ants self.n4bias = ants.n4_bias_field_correction(ants_image, **options)
def predict_mask(in_file: str, masking_config_path=None, input_type: str = 'anat'): """ The image is first resampled into the resolution of the template space, which has a voxel size of 0.2 × 0.2 × 0.2. This is done with the Resample command from the FSL library which is an analysis tool for FMRI, MRI and DTI brain imaging data. Then, the image is preprocessed using the preprocessing methods of the model class. The predictions of the model are reconstructed to a 3D mask via the command Nifit1Image from nibabel. This is done using the same affine space as the input image. The latter is then reshaped into the original shape inverting the preprocessing step, either with the opencv resize method or by cropping. Additionally, the binary mask is resampled into its original affine space, before being multiplied with the brain image to extract the ROI. Parameters ---------- in_file : str path to the file that is to be masked masking_config_path : str path to the masking config. The masking config is a json file. All parameters have default values that will be set in the "get_masking_opts" method. The masking config may contain following parameters (if any of them is not given in the config, the default value will be taken from mlebe/masking/config/default_schema.json): model_folder_path: str The path to the pretrained model. If not set the default mlebe model will be selected. use_cuda: bool boolean indicating if cuda will be used for the masking visualisation_path: str if set, the masking predictions will be saved to this destination. crop_values: if set, the input bids images will be cropped with given values in the x-y dimensions. bias_field_correction: dict If set, the input image will be bias corrected before given as input to the model. The parameter of the bias correction can be given as a dictionary. The default values can be found in the default_schema.json config. input_type : str either 'func' for CDV or BOLD contrast or 'anat' for T2 contrast Returns ------- resampled_mask_path : str path to the mask nii_path_masked : str path to the masked image """ import os from os import path from pathlib import Path import ants import nibabel as nib import numpy as np import pandas as pd from ants.registration import resample_image from nipype.interfaces.fsl.maths import MeanImage from mlebe import log from mlebe.masking.utils import get_mask, get_mlebe_models, get_biascorrect_opts_defaults from mlebe.masking.utils import remove_outliers, get_masking_opts, crop_bids_image, \ reconstruct_image, pad_to_shape, get_model_config log.info( f'Starting masking of {in_file} with config {masking_config_path}.') masking_opts = get_masking_opts(masking_config_path, input_type) if masking_opts['masked_dir']: masked_dir = masking_opts['masked_dir'] df_selection = pd.read_csv(f'{masked_dir}/data_selection.csv') df_selection = df_selection.loc[df_selection.path.str.endswith( in_file)] nii_path_masked = df_selection.masked_path.item() resampled_mask_path = df_selection.mask_path.item() assert nii_path_masked, f'nii_path_masked not found for {in_file}' assert resampled_mask_path, f'nii_path_masked not found for {resampled_mask_path}' assert Path(nii_path_masked).exists( ), f'nii_path_masked {nii_path_masked} does not exist.' assert Path(resampled_mask_path).exists( ), f'resampled_mask_path {resampled_mask_path} does not exist.' return nii_path_masked, [resampled_mask_path], resampled_mask_path if 'model_folder_path' not in masking_opts or not masking_opts[ 'model_folder_path']: # if no model_folder_path is given in the config, the default models are selected. masking_opts['model_folder_path'] = get_mlebe_models(input_type) model_config = get_model_config(masking_opts) input = in_file if input_type == 'func': tMean_path = 'tMean_.nii.gz' mean_image = MeanImage(in_file=input, dimension='T', out_file=tMean_path) mean_image.run() # command = 'fslmaths {a} -Tmean {b}'.format(a=input, b=tMean_path) # log.info(f'Executing command "{command}"') # os.system(command) assert Path(tMean_path).exists() input = tMean_path resampled_path = 'resampled_input.nii.gz' resampled_nii_path = path.abspath(path.expanduser(resampled_path)) if masking_opts['testing']: resampled_nii = resample_image(ants.image_read(str(input)), (0.2, 0.2, 0.2), False) nib.save(resampled_nii, resampled_nii_path) else: resample_cmd = 'ResampleImage 3 {input} '.format( input=input) + resampled_nii_path + ' 0.2x0.2x0.2' os.system(resample_cmd) log.info(f'Resample image with "{resample_cmd}"') if 'crop_values' in masking_opts and masking_opts['crop_values']: crop_bids_image(resampled_nii_path, masking_opts['crop_values']) """ Bias correction """ if 'bias_field_correction' in masking_opts and masking_opts[ 'bias_field_correction']: bias_correction_config = get_biascorrect_opts_defaults(masking_opts) bias_corrected_path = path.abspath( path.expanduser('corrected_input.nii.gz')) if masking_opts['testing']: convergence_args = bias_correction_config['convergence'].strip( '][').split(', ') iters = [int(elem) for elem in convergence_args[0].split('x')] tol = float(convergence_args[1]) bias_corrected = ants.n4_bias_field_correction( ants.image_read(resampled_nii_path), bias_correction_config['bspline_fitting'], convergence={ 'iters': iters, 'tol': tol }, shrink_factor=bias_correction_config['shrink_factor']) nib.save(bias_corrected, bias_corrected_path) else: command = 'N4BiasFieldCorrection --bspline-fitting {} -d 3 --input-image {} --convergence {} --output {} ' \ '--shrink-factor {}'.format( bias_correction_config['bspline_fitting'], resampled_nii_path, bias_correction_config['convergence'], bias_corrected_path, bias_correction_config['shrink_factor']) os.system(command) log.info(f'Apply bias correction with "{command}"') else: bias_corrected_path = resampled_nii_path image = nib.load(bias_corrected_path) in_file_data = image.get_data() """ Getting the mask """ ori_shape = np.moveaxis(in_file_data, 2, 0).shape in_file_data, mask_pred, network_input = get_mask( model_config, in_file_data, ori_shape, use_cuda=masking_opts['use_cuda']) mask_pred = remove_outliers(mask_pred) if 'visualisation_path' in masking_opts and masking_opts[ 'visualisation_path']: log.info(f'visualisation_path is {masking_opts["visualisation_path"]}') save_visualisation(masking_opts, in_file, network_input, mask_pred) """ Reconstruct to original image size """ resized = reconstruct_image(ori_shape, mask_pred) resized_path = 'resized_mask.nii.gz' resized_path = path.abspath(path.expanduser(resized_path)) resized_mask = nib.Nifti1Image(resized, image.affine, image.header) nib.save(resized_mask, resized_path) # get voxel sizes from input input_image = nib.load(input) input_img_affine = input_image.affine voxel_sizes = nib.affines.voxel_sizes(input_img_affine) resampled_mask_path = 'resampled_mask.nii.gz' resampled_mask_path = path.abspath(path.expanduser(resampled_mask_path)) if masking_opts['testing']: resized_mask = ants.image_read(resized_path) resampled_mask_data = resample_image( resized_mask, (voxel_sizes[0], voxel_sizes[1], voxel_sizes[2]), False, 1) else: resample_cmd = 'ResampleImage 3 {input} '.format( input=resized_path ) + ' ' + resampled_mask_path + ' {x}x{y}x{z} '.format( x=voxel_sizes[0], y=voxel_sizes[1], z=voxel_sizes[2]) + ' 0 1' log.info(f'Resample image with "{resample_cmd}"') os.system(resample_cmd) resampled_mask = nib.load(resampled_mask_path) resampled_mask_data = resampled_mask.get_data() input_image_data = input_image.get_data() if resampled_mask_data.shape != input_image_data.shape: resampled_mask_data = pad_to_shape(resampled_mask_data, input_image_data) if masking_opts['testing']: nib.save(resampled_mask_data, resampled_mask_path) resampled_mask_data = resampled_mask_data.numpy() else: nib.save( nib.Nifti1Image(resampled_mask_data, input_image.affine, input_image.header), resampled_mask_path) """ Masking of the input image """ log.info('Masking the input image with the generated mask.') masked_image = np.multiply(resampled_mask_data, input_image_data).astype( 'float32' ) # nibabel gives a non-helpful error if trying to save data that has dtype float64 nii_path_masked = 'masked_output.nii.gz' nii_path_masked = path.abspath(path.expanduser(nii_path_masked)) masked_image = nib.Nifti1Image(masked_image, input_image.affine, input_image.header) nib.save(masked_image, nii_path_masked) log.info(f'Masking of input image {in_file} finished successfully.') # f/s_biascorrect takes a list as input for the mask while biascorrect takes directly the path return nii_path_masked, [resampled_mask_path], resampled_mask_path
def arterial_lesion_segmentation(image, antsxnet_cache_directory=None, verbose=False): """ Perform arterial lesion segmentation using U-net. Arguments --------- image : ANTsImage input image antsxnet_cache_directory : string Destination directory for storing the downloaded template and model weights. Since these can be resused, if is None, these data will be downloaded to a ~/.keras/ANTsXNet/. verbose : boolean Print progress to the screen. Returns ------- Foreground probability image. Example ------- >>> output = arterial_lesion_segmentation(histology_image) """ from ..architectures import create_unet_model_2d from ..utilities import get_pretrained_network if image.dimension != 2: raise ValueError("Image dimension must be 2.") if antsxnet_cache_directory == None: antsxnet_cache_directory = "ANTsXNet" channel_size = 1 weights_file_name = get_pretrained_network( "arterialLesionWeibinShi", antsxnet_cache_directory=antsxnet_cache_directory) resampled_image_size = (512, 512) unet_model = create_unet_model_2d( (*resampled_image_size, channel_size), number_of_outputs=1, mode="sigmoid", number_of_filters=(64, 96, 128, 256, 512), convolution_kernel_size=(3, 3), deconvolution_kernel_size=(2, 2), dropout_rate=0.0, weight_decay=0, additional_options=("initialConvolutionKernelSize[5]", "attentionGating")) unet_model.load_weights(weights_file_name) if verbose == True: print("Preprocessing: Resampling and N4 bias correction.") preprocessed_image = ants.image_clone(image) preprocessed_image = preprocessed_image / preprocessed_image.max() preprocessed_image = ants.resample_image(preprocessed_image, resampled_image_size, use_voxels=True, interp_type=0) mask = ants.image_clone(preprocessed_image) * 0 + 1 preprocessed_image = ants.n4_bias_field_correction(preprocessed_image, mask=mask, shrink_factor=2, return_bias_field=False, verbose=verbose) batchX = np.expand_dims(preprocessed_image.numpy(), axis=0) batchX = np.expand_dims(batchX, axis=-1) batchX = (batchX - batchX.min()) / (batchX.max() - batchX.min()) predicted_data = unet_model.predict(batchX, verbose=int(verbose)) origin = preprocessed_image.origin spacing = preprocessed_image.spacing direction = preprocessed_image.direction foreground_probability_image = ants.from_numpy(np.squeeze( predicted_data[0, :, :, 0]), origin=origin, spacing=spacing, direction=direction) if verbose == True: print("Post-processing: resampling to original space.") foreground_probability_image = ants.resample_image_to_target( foreground_probability_image, image) return (foreground_probability_image)
outputDirectory = baseDirectory + 'OutputANTsPy/' if not os.path.isdir( outputDirectory ): os.mkdir( outputDirectory ) outputPrefix = outputDirectory + 'antspy' numberOfOuterIterations = 5 image = ants.image_read( dataDirectory + 'KKI2009-01-MPRAGE_slice150.nii.gz', dimension = 2 ) mask = ants.image_read( dataDirectory + 'KKI2009-01-MPRAGE_slice150_mask.nii.gz', dimension = 2 ) weightMask = None for i in range( numberOfOuterIterations ): print( "*************** N4 <---> Atropos iteration ", i, " ******************\n" ) n4Results = ants.n4_bias_field_correction( image, mask = mask, weight_mask = weightMask, verbose = True ) image = n4Results atroposResults = ants.atropos( a = image, x = mask ) onesImage = ants.make_image( image.shape, voxval = 0, spacing = ants.get_spacing( image ), origin = ants.get_origin( image ), direction = ants.get_direction( image ) ) weightMask = atroposResults['probabilityimages'][1] *\ ( onesImage - atroposResults['probabilityimages'][0] ) *\ ( onesImage - atroposResults['probabilityimages'][2] ) +\ atroposResults['probabilityimages'][2] *\ ( onesImage - atroposResults['probabilityimages'][1] ) *\ ( onesImage - atroposResults['probabilityimages'][0] ) ants.image_write( image, outputPrefix + "N4Corrected.nii.gz" ) ants.image_write( atroposResults['segmentation'], outputPrefix + "AtroposSegmentation.nii.gz" )
def deep_flash(t1, t2=None, do_preprocessing=True, use_rank_intensity=True, antsxnet_cache_directory=None, verbose=False): """ Hippocampal/Enthorhinal segmentation using "Deep Flash" Perform hippocampal/entorhinal segmentation in T1 and T1/T2 images using labels from Mike Yassa's lab https://faculty.sites.uci.edu/myassa/ The labeling is as follows: Label 0 : background Label 5 : left aLEC Label 6 : right aLEC Label 7 : left pMEC Label 8 : right pMEC Label 9 : left perirhinal Label 10: right perirhinal Label 11: left parahippocampal Label 12: right parahippocampal Label 13: left DG/CA2/CA3/CA4 Label 14: right DG/CA2/CA3/CA4 Label 15: left CA1 Label 16: right CA1 Label 17: left subiculum Label 18: right subiculum Preprocessing on the training data consisted of: * n4 bias correction, * affine registration to the "deep flash" template. which is performed on the input images if do_preprocessing = True. Arguments --------- t1 : ANTsImage raw or preprocessed 3-D T1-weighted brain image. t2 : ANTsImage Optional 3-D T2-weighted brain image. If specified, it is assumed to be pre-aligned to the t1. do_preprocessing : boolean See description above. use_rank_intensity : boolean If false, use histogram matching with cropped template ROI. Otherwise, use a rank intensity transform on the cropped ROI. antsxnet_cache_directory : string Destination directory for storing the downloaded template and model weights. Since these can be resused, if is None, these data will be downloaded to a ~/.keras/ANTsXNet/. verbose : boolean Print progress to the screen. Returns ------- List consisting of the segmentation image and probability images for each label and foreground. Example ------- >>> image = ants.image_read("t1.nii.gz") >>> flash = deep_flash(image) """ from ..architectures import create_unet_model_3d from ..utilities import get_pretrained_network from ..utilities import get_antsxnet_data from ..utilities import brain_extraction if t1.dimension != 3: raise ValueError("Image dimension must be 3.") if antsxnet_cache_directory == None: antsxnet_cache_directory = "ANTsXNet" ################################ # # Options temporarily taken from the user # ################################ # use_hierarchical_parcellation : boolean # If True, use u-net model with additional outputs of the medial temporal lobe # region, hippocampal, and entorhinal/perirhinal/parahippocampal regions. Otherwise # the only additional output is the medial temporal lobe. # # use_contralaterality : boolean # Use both hemispherical models to also predict the corresponding contralateral # segmentation and use both sets of priors to produce the results. Mainly used # for debugging. use_hierarchical_parcellation = True use_contralaterality = True ################################ # # Preprocess images # ################################ t1_preprocessed = t1 t1_mask = None t1_preprocessed_flipped = None t1_template = ants.image_read( get_antsxnet_data("deepFlashTemplateT1SkullStripped")) template_transforms = None if do_preprocessing: if verbose == True: print("Preprocessing T1.") # Brain extraction probability_mask = brain_extraction( t1_preprocessed, modality="t1", antsxnet_cache_directory=antsxnet_cache_directory, verbose=verbose) t1_mask = ants.threshold_image(probability_mask, 0.5, 1, 1, 0) t1_preprocessed = t1_preprocessed * t1_mask # Do bias correction t1_preprocessed = ants.n4_bias_field_correction(t1_preprocessed, t1_mask, shrink_factor=4, verbose=verbose) # Warp to template registration = ants.registration( fixed=t1_template, moving=t1_preprocessed, type_of_transform="antsRegistrationSyNQuickRepro[a]", verbose=verbose) template_transforms = dict(fwdtransforms=registration['fwdtransforms'], invtransforms=registration['invtransforms']) t1_preprocessed = registration['warpedmovout'] if use_contralaterality: t1_preprocessed_array = t1_preprocessed.numpy() t1_preprocessed_array_flipped = np.flip(t1_preprocessed_array, axis=0) t1_preprocessed_flipped = ants.from_numpy( t1_preprocessed_array_flipped, origin=t1_preprocessed.origin, spacing=t1_preprocessed.spacing, direction=t1_preprocessed.direction) t2_preprocessed = t2 t2_preprocessed_flipped = None t2_template = None if t2 is not None: t2_template = ants.image_read( get_antsxnet_data("deepFlashTemplateT2SkullStripped")) t2_template = ants.copy_image_info(t1_template, t2_template) if do_preprocessing: if verbose == True: print("Preprocessing T2.") # Brain extraction t2_preprocessed = t2_preprocessed * t1_mask # Do bias correction t2_preprocessed = ants.n4_bias_field_correction(t2_preprocessed, t1_mask, shrink_factor=4, verbose=verbose) # Warp to template t2_preprocessed = ants.apply_transforms( fixed=t1_template, moving=t2_preprocessed, transformlist=template_transforms['fwdtransforms'], verbose=verbose) if use_contralaterality: t2_preprocessed_array = t2_preprocessed.numpy() t2_preprocessed_array_flipped = np.flip(t2_preprocessed_array, axis=0) t2_preprocessed_flipped = ants.from_numpy( t2_preprocessed_array_flipped, origin=t2_preprocessed.origin, spacing=t2_preprocessed.spacing, direction=t2_preprocessed.direction) probability_images = list() labels = (0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18) image_size = (64, 64, 96) ################################ # # Process left/right in split networks # ################################ ################################ # # Download spatial priors # ################################ spatial_priors_file_name_path = get_antsxnet_data( "deepFlashPriors", antsxnet_cache_directory=antsxnet_cache_directory) spatial_priors = ants.image_read(spatial_priors_file_name_path) priors_image_list = ants.ndimage_to_list(spatial_priors) for i in range(len(priors_image_list)): priors_image_list[i] = ants.copy_image_info(t1_preprocessed, priors_image_list[i]) labels_left = labels[1::2] priors_image_left_list = priors_image_list[1::2] probability_images_left = list() foreground_probability_images_left = list() lower_bound_left = (76, 74, 56) upper_bound_left = (140, 138, 152) tmp_cropped = ants.crop_indices(t1_preprocessed, lower_bound_left, upper_bound_left) origin_left = tmp_cropped.origin spacing = tmp_cropped.spacing direction = tmp_cropped.direction t1_template_roi_left = ants.crop_indices(t1_template, lower_bound_left, upper_bound_left) t1_template_roi_left = (t1_template_roi_left - t1_template_roi_left.min( )) / (t1_template_roi_left.max() - t1_template_roi_left.min()) * 2.0 - 1.0 t2_template_roi_left = None if t2_template is not None: t2_template_roi_left = ants.crop_indices(t2_template, lower_bound_left, upper_bound_left) t2_template_roi_left = (t2_template_roi_left - t2_template_roi_left.min()) / ( t2_template_roi_left.max() - t2_template_roi_left.min()) * 2.0 - 1.0 labels_right = labels[2::2] priors_image_right_list = priors_image_list[2::2] probability_images_right = list() foreground_probability_images_right = list() lower_bound_right = (20, 74, 56) upper_bound_right = (84, 138, 152) tmp_cropped = ants.crop_indices(t1_preprocessed, lower_bound_right, upper_bound_right) origin_right = tmp_cropped.origin t1_template_roi_right = ants.crop_indices(t1_template, lower_bound_right, upper_bound_right) t1_template_roi_right = ( t1_template_roi_right - t1_template_roi_right.min() ) / (t1_template_roi_right.max() - t1_template_roi_right.min()) * 2.0 - 1.0 t2_template_roi_right = None if t2_template is not None: t2_template_roi_right = ants.crop_indices(t2_template, lower_bound_right, upper_bound_right) t2_template_roi_right = (t2_template_roi_right - t2_template_roi_right.min()) / ( t2_template_roi_right.max() - t2_template_roi_right.min()) * 2.0 - 1.0 ################################ # # Create model # ################################ channel_size = 1 + len(labels_left) if t2 is not None: channel_size += 1 number_of_classification_labels = 1 + len(labels_left) unet_model = create_unet_model_3d( (*image_size, channel_size), number_of_outputs=number_of_classification_labels, mode="classification", number_of_filters=(32, 64, 96, 128, 256), convolution_kernel_size=(3, 3, 3), deconvolution_kernel_size=(2, 2, 2), dropout_rate=0.0, weight_decay=0) penultimate_layer = unet_model.layers[-2].output # medial temporal lobe output1 = Conv3D( filters=1, kernel_size=(1, 1, 1), activation='sigmoid', kernel_regularizer=regularizers.l2(0.0))(penultimate_layer) if use_hierarchical_parcellation: # EC, perirhinal, and parahippo. output2 = Conv3D( filters=1, kernel_size=(1, 1, 1), activation='sigmoid', kernel_regularizer=regularizers.l2(0.0))(penultimate_layer) # Hippocampus output3 = Conv3D( filters=1, kernel_size=(1, 1, 1), activation='sigmoid', kernel_regularizer=regularizers.l2(0.0))(penultimate_layer) unet_model = Model( inputs=unet_model.input, outputs=[unet_model.output, output1, output2, output3]) else: unet_model = Model(inputs=unet_model.input, outputs=[unet_model.output, output1]) ################################ # # Left: build model and load weights # ################################ network_name = 'deepFlashLeftT1' if t2 is not None: network_name = 'deepFlashLeftBoth' if use_hierarchical_parcellation: network_name += "Hierarchical" if use_rank_intensity: network_name += "_ri" if verbose: print("DeepFlash: retrieving model weights (left).") weights_file_name = get_pretrained_network( network_name, antsxnet_cache_directory=antsxnet_cache_directory) unet_model.load_weights(weights_file_name) ################################ # # Left: do prediction and normalize to native space # ################################ if verbose: print("Prediction (left).") batchX = None if use_contralaterality: batchX = np.zeros((2, *image_size, channel_size)) else: batchX = np.zeros((1, *image_size, channel_size)) t1_cropped = ants.crop_indices(t1_preprocessed, lower_bound_left, upper_bound_left) if use_rank_intensity: t1_cropped = ants.rank_intensity(t1_cropped) else: t1_cropped = ants.histogram_match_image(t1_cropped, t1_template_roi_left, 255, 64, False) batchX[0, :, :, :, 0] = t1_cropped.numpy() if use_contralaterality: t1_cropped = ants.crop_indices(t1_preprocessed_flipped, lower_bound_left, upper_bound_left) if use_rank_intensity: t1_cropped = ants.rank_intensity(t1_cropped) else: t1_cropped = ants.histogram_match_image(t1_cropped, t1_template_roi_left, 255, 64, False) batchX[1, :, :, :, 0] = t1_cropped.numpy() if t2 is not None: t2_cropped = ants.crop_indices(t2_preprocessed, lower_bound_left, upper_bound_left) if use_rank_intensity: t2_cropped = ants.rank_intensity(t2_cropped) else: t2_cropped = ants.histogram_match_image(t2_cropped, t2_template_roi_left, 255, 64, False) batchX[0, :, :, :, 1] = t2_cropped.numpy() if use_contralaterality: t2_cropped = ants.crop_indices(t2_preprocessed_flipped, lower_bound_left, upper_bound_left) if use_rank_intensity: t2_cropped = ants.rank_intensity(t2_cropped) else: t2_cropped = ants.histogram_match_image( t2_cropped, t2_template_roi_left, 255, 64, False) batchX[1, :, :, :, 1] = t2_cropped.numpy() for i in range(len(priors_image_left_list)): cropped_prior = ants.crop_indices(priors_image_left_list[i], lower_bound_left, upper_bound_left) for j in range(batchX.shape[0]): batchX[j, :, :, :, i + (channel_size - len(labels_left))] = cropped_prior.numpy() predicted_data = unet_model.predict(batchX, verbose=verbose) for i in range(1 + len(labels_left)): for j in range(predicted_data[0].shape[0]): probability_image = \ ants.from_numpy(np.squeeze(predicted_data[0][j, :, :, :, i]), origin=origin_left, spacing=spacing, direction=direction) if i > 0: probability_image = ants.decrop_image(probability_image, t1_preprocessed * 0) else: probability_image = ants.decrop_image(probability_image, t1_preprocessed * 0 + 1) if j == 1: # flipped probability_array_flipped = np.flip(probability_image.numpy(), axis=0) probability_image = ants.from_numpy( probability_array_flipped, origin=probability_image.origin, spacing=probability_image.spacing, direction=probability_image.direction) if do_preprocessing: probability_image = ants.apply_transforms( fixed=t1, moving=probability_image, transformlist=template_transforms['invtransforms'], whichtoinvert=[True], interpolator="linear", verbose=verbose) if j == 0: # not flipped probability_images_left.append(probability_image) else: # flipped probability_images_right.append(probability_image) ################################ # # Left: do prediction of mtl, hippocampal, and ec regions and normalize to native space # ################################ for i in range(1, len(predicted_data)): for j in range(predicted_data[i].shape[0]): probability_image = \ ants.from_numpy(np.squeeze(predicted_data[i][j, :, :, :, 0]), origin=origin_left, spacing=spacing, direction=direction) probability_image = ants.decrop_image(probability_image, t1_preprocessed * 0) if j == 1: # flipped probability_array_flipped = np.flip(probability_image.numpy(), axis=0) probability_image = ants.from_numpy( probability_array_flipped, origin=probability_image.origin, spacing=probability_image.spacing, direction=probability_image.direction) if do_preprocessing: probability_image = ants.apply_transforms( fixed=t1, moving=probability_image, transformlist=template_transforms['invtransforms'], whichtoinvert=[True], interpolator="linear", verbose=verbose) if j == 0: # not flipped foreground_probability_images_left.append(probability_image) else: foreground_probability_images_right.append(probability_image) ################################ # # Right: build model and load weights # ################################ network_name = 'deepFlashRightT1' if t2 is not None: network_name = 'deepFlashRightBoth' if use_hierarchical_parcellation: network_name += "Hierarchical" if use_rank_intensity: network_name += "_ri" if verbose: print("DeepFlash: retrieving model weights (right).") weights_file_name = get_pretrained_network( network_name, antsxnet_cache_directory=antsxnet_cache_directory) unet_model.load_weights(weights_file_name) ################################ # # Right: do prediction and normalize to native space # ################################ if verbose: print("Prediction (right).") batchX = None if use_contralaterality: batchX = np.zeros((2, *image_size, channel_size)) else: batchX = np.zeros((1, *image_size, channel_size)) t1_cropped = ants.crop_indices(t1_preprocessed, lower_bound_right, upper_bound_right) if use_rank_intensity: t1_cropped = ants.rank_intensity(t1_cropped) else: t1_cropped = ants.histogram_match_image(t1_cropped, t1_template_roi_right, 255, 64, False) batchX[0, :, :, :, 0] = t1_cropped.numpy() if use_contralaterality: t1_cropped = ants.crop_indices(t1_preprocessed_flipped, lower_bound_right, upper_bound_right) if use_rank_intensity: t1_cropped = ants.rank_intensity(t1_cropped) else: t1_cropped = ants.histogram_match_image(t1_cropped, t1_template_roi_right, 255, 64, False) batchX[1, :, :, :, 0] = t1_cropped.numpy() if t2 is not None: t2_cropped = ants.crop_indices(t2_preprocessed, lower_bound_right, upper_bound_right) if use_rank_intensity: t2_cropped = ants.rank_intensity(t2_cropped) else: t2_cropped = ants.histogram_match_image(t2_cropped, t2_template_roi_right, 255, 64, False) batchX[0, :, :, :, 1] = t2_cropped.numpy() if use_contralaterality: t2_cropped = ants.crop_indices(t2_preprocessed_flipped, lower_bound_right, upper_bound_right) if use_rank_intensity: t2_cropped = ants.rank_intensity(t2_cropped) else: t2_cropped = ants.histogram_match_image( t2_cropped, t2_template_roi_right, 255, 64, False) batchX[1, :, :, :, 1] = t2_cropped.numpy() for i in range(len(priors_image_right_list)): cropped_prior = ants.crop_indices(priors_image_right_list[i], lower_bound_right, upper_bound_right) for j in range(batchX.shape[0]): batchX[j, :, :, :, i + (channel_size - len(labels_right))] = cropped_prior.numpy() predicted_data = unet_model.predict(batchX, verbose=verbose) for i in range(1 + len(labels_right)): for j in range(predicted_data[0].shape[0]): probability_image = \ ants.from_numpy(np.squeeze(predicted_data[0][j, :, :, :, i]), origin=origin_right, spacing=spacing, direction=direction) if i > 0: probability_image = ants.decrop_image(probability_image, t1_preprocessed * 0) else: probability_image = ants.decrop_image(probability_image, t1_preprocessed * 0 + 1) if j == 1: # flipped probability_array_flipped = np.flip(probability_image.numpy(), axis=0) probability_image = ants.from_numpy( probability_array_flipped, origin=probability_image.origin, spacing=probability_image.spacing, direction=probability_image.direction) if do_preprocessing: probability_image = ants.apply_transforms( fixed=t1, moving=probability_image, transformlist=template_transforms['invtransforms'], whichtoinvert=[True], interpolator="linear", verbose=verbose) if j == 0: # not flipped if use_contralaterality: probability_images_right[i] = ( probability_images_right[i] + probability_image) / 2 else: probability_images_right.append(probability_image) else: # flipped probability_images_left[i] = (probability_images_left[i] + probability_image) / 2 ################################ # # Right: do prediction of mtl, hippocampal, and ec regions and normalize to native space # ################################ for i in range(1, len(predicted_data)): for j in range(predicted_data[i].shape[0]): probability_image = \ ants.from_numpy(np.squeeze(predicted_data[i][j, :, :, :, 0]), origin=origin_right, spacing=spacing, direction=direction) probability_image = ants.decrop_image(probability_image, t1_preprocessed * 0) if j == 1: # flipped probability_array_flipped = np.flip(probability_image.numpy(), axis=0) probability_image = ants.from_numpy( probability_array_flipped, origin=probability_image.origin, spacing=probability_image.spacing, direction=probability_image.direction) if do_preprocessing: probability_image = ants.apply_transforms( fixed=t1, moving=probability_image, transformlist=template_transforms['invtransforms'], whichtoinvert=[True], interpolator="linear", verbose=verbose) if j == 0: # not flipped if use_contralaterality: foreground_probability_images_right[ i - 1] = (foreground_probability_images_right[i - 1] + probability_image) / 2 else: foreground_probability_images_right.append( probability_image) else: foreground_probability_images_left[ i - 1] = (foreground_probability_images_left[i - 1] + probability_image) / 2 ################################ # # Combine priors # ################################ probability_background_image = ants.image_clone(t1) * 0 for i in range(1, len(probability_images_left)): probability_background_image += probability_images_left[i] for i in range(1, len(probability_images_right)): probability_background_image += probability_images_right[i] probability_images.append(probability_background_image * -1 + 1) for i in range(1, len(probability_images_left)): probability_images.append(probability_images_left[i]) probability_images.append(probability_images_right[i]) ################################ # # Convert probability images to segmentation # ################################ # image_matrix = ants.image_list_to_matrix(probability_images, t1 * 0 + 1) # segmentation_matrix = np.argmax(image_matrix, axis=0) # segmentation_image = ants.matrix_to_images( # np.expand_dims(segmentation_matrix, axis=0), t1 * 0 + 1)[0] image_matrix = ants.image_list_to_matrix( probability_images[1:(len(probability_images))], t1 * 0 + 1) background_foreground_matrix = np.stack([ ants.image_list_to_matrix([probability_images[0]], t1 * 0 + 1), np.expand_dims(np.sum(image_matrix, axis=0), axis=0) ]) foreground_matrix = np.argmax(background_foreground_matrix, axis=0) segmentation_matrix = (np.argmax(image_matrix, axis=0) + 1) * foreground_matrix segmentation_image = ants.matrix_to_images( np.expand_dims(segmentation_matrix, axis=0), t1 * 0 + 1)[0] relabeled_image = ants.image_clone(segmentation_image) for i in range(len(labels)): relabeled_image[segmentation_image == i] = labels[i] foreground_probability_images = list() for i in range(len(foreground_probability_images_left)): foreground_probability_images.append( foreground_probability_images_left[i] + foreground_probability_images_right[i]) return_dict = None if use_hierarchical_parcellation: return_dict = { 'segmentation_image': relabeled_image, 'probability_images': probability_images, 'medial_temporal_lobe_probability_image': foreground_probability_images[0], 'other_region_probability_image': foreground_probability_images[1], 'hippocampal_probability_image': foreground_probability_images[2] } else: return_dict = { 'segmentation_image': relabeled_image, 'probability_images': probability_images, 'medial_temporal_lobe_probability_image': foreground_probability_images[0] } return (return_dict)
# ants.plot( t1, t1mask, axis=2, overlay_alpha = 0.33 ) t1rig = ants.registration( und * bmask, t1 * t1mask, "BOLDRigid" ) t1reg = ants.registration( und * bmask, t1 * t1mask, "SyNOnly", initialTransform = t1rig['fwdtransforms'], synMetric = 'CC', synSampling = 2, regIterations = (5) ) ########################### # The distortion to the T1 is greatly reduced. # Brain masking # Use the BOLD mask to extract the brain from the t1 t1maskFromBold = ants.apply_transforms( t1, bmask, t1reg['invtransforms'], interpolator = 'nearestNeighbor' ) t1 = ants.n4_bias_field_correction( t1, t1mask, 8 ).n4_bias_field_correction( t1mask, 4 ) bmask = ants.apply_transforms( und, t1mask, t1reg['fwdtransforms'], interpolator = 'nearestNeighbor' ).morphology("close",3) ofn = rdir + "features/LS" + id + "_mask_py.nii.gz" ants.image_write( bmask, ofn ) t1toBOLD = ants.apply_transforms( und, t1, t1reg['fwdtransforms'] ) ofn = rdir + "features/LS" + id + "_t1ToBold_py.nii.gz" ants.image_write( t1toBOLD, ofn ) ## Tissue segmentation # a simple method ################################################ qt1 = ants.iMath_truncate_intensity( t1, 0, 0.95 ) t1seg = ants.kmeans_segmentation( qt1, 3, t1mask, 0.2 ) volumes = ants.label_stats( t1seg['segmentation'], t1seg['segmentation'] )
print("Download: test image") url_image = "https://github.com/ANTsXNet/BrainExtraction/blob/master/Data/Example/1097782_defaced_MPRAGE.nii.gz?raw=true" target_file_image = tempfile.NamedTemporaryFile(suffix=".nii.gz", dir=temp_directory.name) target_file_image.close() target_file_image_name = target_file_image.name if not path.exists(target_file_image_name): r = requests.get(url_image) with open(target_file_image_name, 'wb') as f: f.write(r.content) image = ants.image_read(target_file_image_name) print("Preprocessing: bias correction") image_n4 = ants.n4_bias_field_correction(image) image_n4 = ants.image_math(image_n4, 'Normalize') * 255.0 print("Preprocessing: thresholding") image_n4_array = ((image_n4.numpy()).flatten()) image_n4_nonzero = image_n4_array[(image_n4_array > 0).nonzero()] image_robust_range = np.quantile(image_n4_nonzero, (0.02, 0.98)) threshold_value = 0.10 * (image_robust_range[1] - image_robust_range[0]) + image_robust_range[0] thresholded_mask = ants.threshold_image(image_n4, -10000, threshold_value, 0, 1) thresholded_image = image_n4 * thresholded_mask print("Preprocessing: resampling") image_resampled = ants.resample_image(thresholded_image, (256, 256, 256), True) batchX = np.expand_dims(image_resampled.numpy(), axis=0)
def mask_one(self, bids_path: str, elem, masking_opts, model, model_config) -> Tuple[Path, Path]: bids_file = ants.image_read(bids_path) bids_data = bids_file.numpy() bids_file_nib = nib.load(bids_path) # resample bids image into the voxel space for which the masking model was trained. resampled_bids: ants.ANTsImage = resample_image( bids_file, (0.2, 0.2, 0.2), False) # crop bids image one the side with given values to alleviate the task of the masking model. if 'crop_values' in masking_opts and masking_opts['crop_values']: raise NotImplemented('crop_values not yet implemented.') crop_values = masking_opts['crop_values'] cropped = resampled_bids[crop_values[0]:resampled_bids.shape[0] - crop_values[1], ...] resampled_bids = nib.Nifti1Image(cropped, resampled_bids.affine, resampled_bids.header) if 'bias_field_correction' in masking_opts and masking_opts[ 'bias_field_correction']: bias_correction_config = get_biascorrect_opts_defaults( masking_opts) convergence_args = bias_correction_config['convergence'].strip( '][').split(', ') iters = [int(elem) for elem in convergence_args[0].split('x')] tol = float(convergence_args[1]) resampled_bids = ants.n4_bias_field_correction( resampled_bids, bias_correction_config['bspline_fitting'], convergence={ 'iters': iters, 'tol': tol }, shrink_factor=bias_correction_config['shrink_factor']) # get the mask in_data = resampled_bids.numpy() resampled_shape = np.moveaxis(in_data, 2, 0).shape in_file_data, mask_pred, model_input = get_mask( model_config, in_data, resampled_shape, use_cuda=masking_opts['use_cuda'], model=model) mask_pred = remove_outliers(mask_pred) resampled_mask = self.reconstruct_to_imgsize(bids_file, resampled_shape, mask_pred, resampled_bids) resampled_mask_data = resampled_mask.numpy() if resampled_mask_data.shape != bids_data.shape: resampled_mask_data = pad_to_shape(resampled_mask_data, bids_data) # Masking of the input image masked_image_data = np.multiply(resampled_mask_data, bids_file.numpy()) \ .astype('float32') # nibabel gives a non-helpful error if trying to save data that has dtype float64 masked_image = nib.Nifti1Image(masked_image_data, bids_file_nib.affine, bids_file_nib.header) if 'visualisation_path' in masking_opts and masking_opts[ 'visualisation_path']: save_masking_visualisation( masking_opts, Path(bids_path).name, model_input=model_input, predicted_mask=mask_pred, input_data=np.moveaxis(bids_file.numpy(), 2, 0), resampled_mask=np.moveaxis(masked_image_data, 2, 0)) # saving results filename = bids_path.split('/')[-1] out_dir = self.preprocessing_dir / 'masked_bids' / f'sub-{elem.subject}' / f'ses-{elem.session}' / elem.datatype out_dir.mkdir(parents=True, exist_ok=True) mask_path = out_dir / f'mask_{filename}' masked_path = out_dir / f'masked_{filename}' nib.save( nib.Nifti1Image(resampled_mask_data, bids_file_nib.affine, bids_file_nib.header), mask_path) nib.save(masked_image, masked_path) return mask_path, masked_path
def n4_bias_correction(image): import ants as_ants = ants.from_numpy(image) corrected = ants.n4_bias_field_correction(as_ants) return corrected.numpy()
def preprocess_images( atlas_id: int, atlas_csf_id: int, atlas_grey_id: int, atlas_white_id: int, dataset_id: int, replace: bool = False, downsample: float = 3.0, ): atlas = models.Atlas.objects.get(pk=atlas_id) atlas_csf = models.Atlas.objects.get(pk=atlas_csf_id) atlas_grey = models.Atlas.objects.get(pk=atlas_grey_id) atlas_white = models.Atlas.objects.get(pk=atlas_white_id) dataset = models.Dataset.objects.get(pk=dataset_id) print('Downloading atlas files') with NamedTemporaryFile( suffix='atlas.nii') as tmp, atlas.blob.open() as blob: for chunk in blob.chunks(): tmp.write(chunk) atlas_img = ants.image_read(tmp.name) with NamedTemporaryFile( suffix='atlas_csf.nii') as tmp, atlas_csf.blob.open() as blob: for chunk in blob.chunks(): tmp.write(chunk) atlas_csf_img = ants.image_read(tmp.name) with NamedTemporaryFile( suffix='atlas_grey.nii') as tmp, atlas_grey.blob.open() as blob: for chunk in blob.chunks(): tmp.write(chunk) atlas_grey_img = ants.image_read(tmp.name) with NamedTemporaryFile( suffix='atlas_white.nii') as tmp, atlas_white.blob.open() as blob: for chunk in blob.chunks(): tmp.write(chunk) atlas_white_img = ants.image_read(tmp.name) print('Creating mask') priors = [atlas_csf_img, atlas_grey_img, atlas_white_img] mask = priors[0].copy() mask_view = mask.view() for i in range(1, len(priors)): mask_view[priors[i].numpy() > 0] = 1 mask_view[mask_view > 0] = 1 for image in dataset.images.all(): if replace: _delete_preprocessing_artifacts(image) elif _already_preprocessed(image): continue with NamedTemporaryFile( suffix=image.name) as tmp, image.blob.open() as blob: for chunk in blob.chunks(): tmp.write(chunk) input_img = ants.image_read(tmp.name) print(f'Running N4 bias correction: {image.name}') im_n4 = ants.n4_bias_field_correction(input_img) del input_img print(f'Running registration: {image.name}') reg = ants.registration(atlas_img, im_n4) del im_n4 jac_img = ants.create_jacobian_determinant_image( atlas_img, reg['fwdtransforms'][0], 1) jac_img = jac_img.apply(np.abs) reg_model = models.RegisteredImage(source_image=image, atlas=atlas) reg_img = reg['warpedmovout'] with NamedTemporaryFile(suffix='registered.nii') as tmp: ants.image_write(reg_img, tmp.name) reg_model.blob = File(tmp, name='registered.nii') reg_model.save() jac_model = models.JacobianImage(source_image=image, atlas=atlas) with NamedTemporaryFile(suffix='jacobian.nii') as tmp: ants.image_write(jac_img, tmp.name) jac_model.blob = File(tmp, name='jacobian.nii') jac_model.save() print(f'Running segmentation: {image.name}') seg = ants.prior_based_segmentation(reg_img, priors, mask) del reg_img seg_model = models.SegmentedImage(source_image=image, atlas=atlas) with NamedTemporaryFile(suffix='segmented.nii') as tmp: ants.image_write(seg['segmentation'], tmp.name) seg_model.blob = File(tmp, name='segmented.nii') seg_model.save() print(f'Creating feature image: {image.name}') seg_img_view = seg['segmentation'].view() feature_img = seg['segmentation'].copy() feature_img_view = feature_img.view() feature_img_view.fill(0) feature_img_view[seg_img_view == 3] = 1 # 3 is white matter label intensity_img_view = jac_img.view() feature_img_view *= intensity_img_view if downsample > 1: shape = np.round(np.asarray(feature_img.shape) / downsample) feature_img = ants.resample_image(feature_img, shape, True) feature_model = models.FeatureImage(source_image=image, atlas=atlas, downsample_factor=downsample) with NamedTemporaryFile(suffix='feature.nii') as tmp: ants.image_write(feature_img, tmp.name) feature_model.blob = File(tmp, name='feature.nii') feature_model.save() dataset.preprocessing_complete = True dataset.save()
def preprocess( image: NiftiImage, mask: Optional[NiftiImage] = None, resolution: Optional[Tuple[float, float, float]] = None, orientation: str = "RAS", n4_convergence_options: Optional[dict] = None, interp_type: str = "linear", second_n4_with_smoothed_mask: bool = True, ) -> Tuple[NiftiImage, NiftiImage]: """Preprocess an MR image Preprocess an MR image according to a simple scheme: 1) N4 bias field correction 2) resample to X mm x Y mm x Z mm 3) reorient images to RAI Args: image: image to preprocess mask: mask covering the brain of image (none if already skull-stripped) resolution: resolution for resampling. None for no resampling. orientation: reorient the image according to this. See ANTsPy for details. n4_convergence_options: n4 processing options. See ANTsPy for details. interp_type: interpolation type for resampling choices: linear, nearest_neighbor, gaussian, windowed_sinc, bspline second_n4_with_smoothed_mask: do a second N4 with a smoothed mask often improves the bias field correction in the image Returns: preprocessed image and corresponding foreground mask """ if n4_convergence_options is None: n4_convergence_options = {"iters": [200, 200, 200, 200], "tol": 1e-7} logger.debug(f"N4 Options are: {n4_convergence_options}") if isinstance(image, nib.Nifti1Image): image = ants.from_nibabel(image) if mask is not None: if isinstance(mask, nib.Nifti1Image): mask = ants.from_nibabel(mask) else: mask = image.get_mask() logger.debug("Starting bias field correction") image = ants.n4_bias_field_correction(image, convergence=n4_convergence_options) if second_n4_with_smoothed_mask: smoothed_mask = ants.smooth_image(mask, 1.0) logger.debug("Starting 2nd bias field correction") image = ants.n4_bias_field_correction( image, convergence=n4_convergence_options, weight_mask=smoothed_mask, ) if resolution is not None: if resolution != mask.spacing: logger.debug(f"Resampling mask to {resolution}") mask = ants.resample_image( mask, resolution, use_voxels=False, interp_type=interp_type_dict["nearest_neighbor"], ) if resolution != image.spacing: logger.debug(f"Resampling image to {resolution}") image = ants.resample_image( image, resolution, use_voxels=False, interp_type=interp_type_dict[interp_type], ) image = image.reorient_image2(orientation) mask = mask.reorient_image2(orientation) image = image.to_nibabel() mask = mask.to_nibabel() return image, mask