def test_crop_image_example(self): fi = ants.image_read(ants.get_ants_data('r16')) cropped = ants.crop_image(fi) cropped = ants.crop_image(fi, fi, 100) # image not float type cropped = ants.crop_image(fi.clone('unsigned int')) # label image not float cropped = ants.crop_image(fi, fi.clone('unsigned int'), 100)
def test_decrop_image_example(self): fi = ants.image_read(ants.get_ants_data('r16')) mask = ants.get_mask(fi) cropped = ants.crop_image(fi, mask, 1) cropped = ants.smooth_image(cropped, 1) decropped = ants.decrop_image(cropped, fi) # image not float cropped = ants.crop_image(fi.clone('unsigned int'), mask, 1) # full image not float cropped = ants.crop_image(fi, mask.clone('unsigned int'), 1)
def hippmapp3r_segmentation(t1, do_preprocessing=True, antsxnet_cache_directory=None, verbose=False): """ Perform HippMapp3r (hippocampal) segmentation described in https://www.ncbi.nlm.nih.gov/pubmed/31609046 with models and architecture ported from https://github.com/mgoubran/HippMapp3r Additional documentation and attribution resources found at https://hippmapp3r.readthedocs.io/en/latest/ Preprocessing consists of: * n4 bias correction and * brain extraction The input T1 should undergo the same steps. If the input T1 is the raw T1, these steps can be performed by the internal preprocessing, i.e. set do_preprocessing = True Arguments --------- t1 : ANTsImage input image do_preprocessing : boolean See description above. 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 ------- ANTs labeled hippocampal image. Example ------- >>> mask = hippmapp3r_segmentation(t1) """ from ..architectures import create_hippmapp3r_unet_model_3d from ..utilities import preprocess_brain_image from ..utilities import get_pretrained_network from ..utilities import get_antsxnet_data if t1.dimension != 3: raise ValueError("Image dimension must be 3.") if antsxnet_cache_directory == None: antsxnet_cache_directory = "ANTsXNet" if verbose == True: print("************* Preprocessing ***************") print("") t1_preprocessed = t1 if do_preprocessing == True: t1_preprocessing = preprocess_brain_image( t1, truncate_intensity=None, brain_extraction_modality="t1", template=None, do_bias_correction=True, do_denoising=False, antsxnet_cache_directory=antsxnet_cache_directory, verbose=verbose) t1_preprocessed = t1_preprocessing[ "preprocessed_image"] * t1_preprocessing['brain_mask'] if verbose == True: print("************* Initial stage segmentation ***************") print("") # Normalize to mprage_hippmapp3r space if verbose == True: print(" HippMapp3r: template normalization.") template_file_name_path = get_antsxnet_data( "mprage_hippmapp3r", antsxnet_cache_directory=antsxnet_cache_directory) template_image = ants.image_read(template_file_name_path) registration = ants.registration( fixed=template_image, moving=t1_preprocessed, type_of_transform="antsRegistrationSyNQuickRepro[t]", verbose=verbose) image = registration['warpedmovout'] transforms = dict(fwdtransforms=registration['fwdtransforms'], invtransforms=registration['invtransforms']) # Threshold at 10th percentile of non-zero voxels in "robust range (fslmaths)" if verbose == True: print(" HippMapp3r: threshold.") image_array = image.numpy() image_robust_range = np.quantile(image_array[np.where(image_array != 0)], (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, -10000, threshold_value, 0, 1) thresholded_image = image * thresholded_mask # Standardize image if verbose == True: print(" HippMapp3r: standardize.") mean_image = np.mean(thresholded_image[thresholded_mask == 1]) sd_image = np.std(thresholded_image[thresholded_mask == 1]) image_normalized = (image - mean_image) / sd_image image_normalized = image_normalized * thresholded_mask # Trim and resample image if verbose == True: print(" HippMapp3r: trim and resample to (160, 160, 128).") image_cropped = ants.crop_image(image_normalized, thresholded_mask, 1) shape_initial_stage = (160, 160, 128) image_resampled = ants.resample_image(image_cropped, shape_initial_stage, use_voxels=True, interp_type=1) if verbose == True: print(" HippMapp3r: generate first network and download weights.") model_initial_stage = create_hippmapp3r_unet_model_3d( (*shape_initial_stage, 1), do_first_network=True) initial_stage_weights_file_name = get_pretrained_network( "hippMapp3rInitial", antsxnet_cache_directory=antsxnet_cache_directory) model_initial_stage.load_weights(initial_stage_weights_file_name) if verbose == True: print(" HippMapp3r: prediction.") data_initial_stage = np.expand_dims(image_resampled.numpy(), axis=0) data_initial_stage = np.expand_dims(data_initial_stage, axis=-1) mask_array = model_initial_stage.predict(data_initial_stage, verbose=verbose) mask_image_resampled = ants.copy_image_info( image_resampled, ants.from_numpy(np.squeeze(mask_array))) mask_image = ants.resample_image(mask_image_resampled, image.shape, use_voxels=True, interp_type=0) mask_image[mask_image >= 0.5] = 1 mask_image[mask_image < 0.5] = 0 ######################################### # # Perform refined (stage 2) segmentation # if verbose == True: print("") print("") print("************* Refine stage segmentation ***************") print("") mask_array = np.squeeze(mask_array) centroid_indices = np.where(mask_array == 1) centroid = np.zeros((3, )) centroid[0] = centroid_indices[0].mean() centroid[1] = centroid_indices[1].mean() centroid[2] = centroid_indices[2].mean() shape_refine_stage = (112, 112, 64) lower = (np.floor(centroid - 0.5 * np.array(shape_refine_stage)) - 1).astype(int) upper = (lower + np.array(shape_refine_stage)).astype(int) image_trimmed = ants.crop_indices(image_resampled, lower.astype(int), upper.astype(int)) if verbose == True: print(" HippMapp3r: generate second network and download weights.") model_refine_stage = create_hippmapp3r_unet_model_3d( (*shape_refine_stage, 1), do_first_network=False) refine_stage_weights_file_name = get_pretrained_network( "hippMapp3rRefine", antsxnet_cache_directory=antsxnet_cache_directory) model_refine_stage.load_weights(refine_stage_weights_file_name) data_refine_stage = np.expand_dims(image_trimmed.numpy(), axis=0) data_refine_stage = np.expand_dims(data_refine_stage, axis=-1) if verbose == True: print(" HippMapp3r: Monte Carlo iterations (SpatialDropout).") number_of_mci_iterations = 30 prediction_refine_stage = np.zeros(shape_refine_stage) for i in range(number_of_mci_iterations): tf.random.set_seed(i) if verbose == True: print(" Monte Carlo iteration", i + 1, "out of", number_of_mci_iterations) prediction_refine_stage = \ (np.squeeze(model_refine_stage.predict(data_refine_stage, verbose=verbose)) + \ i * prediction_refine_stage ) / (i + 1) prediction_refine_stage_array = np.zeros(image_resampled.shape) prediction_refine_stage_array[lower[0]:upper[0], lower[1]:upper[1], lower[2]:upper[2]] = prediction_refine_stage probability_mask_refine_stage_resampled = ants.copy_image_info( image_resampled, ants.from_numpy(prediction_refine_stage_array)) segmentation_image_resampled = ants.label_clusters(ants.threshold_image( probability_mask_refine_stage_resampled, 0.0, 0.5, 0, 1), min_cluster_size=10) segmentation_image_resampled[segmentation_image_resampled > 2] = 0 geom = ants.label_geometry_measures(segmentation_image_resampled) if len(geom['VolumeInMillimeters']) < 2: raise ValueError("Error: left and right hippocampus not found.") if geom['Centroid_x'][0] < geom['Centroid_x'][1]: segmentation_image_resampled[segmentation_image_resampled == 1] = 3 segmentation_image_resampled[segmentation_image_resampled == 2] = 1 segmentation_image_resampled[segmentation_image_resampled == 3] = 2 segmentation_image = ants.apply_transforms( fixed=t1, moving=segmentation_image_resampled, transformlist=transforms['invtransforms'], whichtoinvert=[True], interpolator="genericLabel", verbose=verbose) return (segmentation_image)
def sysu_media_wmh_segmentation(flair, t1=None, use_ensemble=True, antsxnet_cache_directory=None, verbose=False): """ Perform WMH segmentation using the winning submission in the MICCAI 2017 challenge by the sysu_media team using FLAIR or T1/FLAIR. The MICCAI challenge is discussed in https://pubmed.ncbi.nlm.nih.gov/30908194/ with the sysu_media's team entry is discussed in https://pubmed.ncbi.nlm.nih.gov/30125711/ with the original implementation available here: https://github.com/hongweilibran/wmh_ibbmTum The original implementation used global thresholding as a quick brain extraction approach. Due to possible generalization difficulties, we leave such post-processing steps to the user. For brain or white matter masking see functions brain_extraction or deep_atropos, respectively. Arguments --------- flair : ANTsImage input 3-D FLAIR brain image (not skull-stripped). t1 : ANTsImage input 3-D T1 brain image (not skull-stripped). use_ensemble : boolean check whether to use all 3 sets of weights. 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 ------- WMH segmentation probability image Example ------- >>> image = ants.image_read("flair.nii.gz") >>> probability_mask = sysu_media_wmh_segmentation(image) """ from ..architectures import create_sysu_media_unet_model_2d from ..utilities import get_pretrained_network from ..utilities import pad_or_crop_image_to_size from ..utilities import preprocess_brain_image from ..utilities import binary_dice_coefficient if flair.dimension != 3: raise ValueError("Image dimension must be 3.") if antsxnet_cache_directory == None: antsxnet_cache_directory = "ANTsXNet" image_size = (200, 200) ################################ # # Preprocess images # ################################ def closest_simplified_direction_matrix(direction): closest = (np.abs(direction) + 0.5).astype(int).astype(float) closest[direction < 0] *= -1.0 return closest simplified_direction = closest_simplified_direction_matrix(flair.direction) flair_preprocessing = preprocess_brain_image( flair, truncate_intensity=None, brain_extraction_modality=None, do_bias_correction=False, do_denoising=False, antsxnet_cache_directory=antsxnet_cache_directory, verbose=verbose) flair_preprocessed = flair_preprocessing["preprocessed_image"] flair_preprocessed.set_direction(simplified_direction) flair_preprocessed.set_origin((0, 0, 0)) flair_preprocessed.set_spacing((1, 1, 1)) number_of_channels = 1 t1_preprocessed = None if t1 is not None: t1_preprocessing = preprocess_brain_image( t1, truncate_intensity=None, brain_extraction_modality=None, do_bias_correction=False, do_denoising=False, antsxnet_cache_directory=antsxnet_cache_directory, verbose=verbose) t1_preprocessed = t1_preprocessing["preprocessed_image"] t1_preprocessed.set_direction(simplified_direction) t1_preprocessed.set_origin((0, 0, 0)) t1_preprocessed.set_spacing((1, 1, 1)) number_of_channels = 2 ################################ # # Reorient images # ################################ reference_image = ants.make_image((256, 256, 256), voxval=0, spacing=(1, 1, 1), origin=(0, 0, 0), direction=np.identity(3)) center_of_mass_reference = np.floor( ants.get_center_of_mass(reference_image * 0 + 1)) center_of_mass_image = np.floor( ants.get_center_of_mass(flair_preprocessed)) translation = np.asarray(center_of_mass_image) - np.asarray( center_of_mass_reference) xfrm = ants.create_ants_transform( transform_type="Euler3DTransform", center=np.asarray(center_of_mass_reference), translation=translation) flair_preprocessed_warped = ants.apply_ants_transform_to_image( xfrm, flair_preprocessed, reference_image, interpolation="nearestneighbor") crop_image = ants.image_clone(flair_preprocessed) * 0 + 1 crop_image_warped = ants.apply_ants_transform_to_image( xfrm, crop_image, reference_image, interpolation="nearestneighbor") flair_preprocessed_warped = ants.crop_image(flair_preprocessed_warped, crop_image_warped, 1) if t1 is not None: t1_preprocessed_warped = ants.apply_ants_transform_to_image( xfrm, t1_preprocessed, reference_image, interpolation="nearestneighbor") t1_preprocessed_warped = ants.crop_image(t1_preprocessed_warped, crop_image_warped, 1) ################################ # # Gaussian normalize intensity # ################################ mean_flair = flair_preprocessed.mean() std_flair = flair_preprocessed.std() if number_of_channels == 2: mean_t1 = t1_preprocessed.mean() std_t1 = t1_preprocessed.std() flair_preprocessed_warped = (flair_preprocessed_warped - mean_flair) / std_flair if number_of_channels == 2: t1_preprocessed_warped = (t1_preprocessed_warped - mean_t1) / std_t1 ################################ # # Build models and load weights # ################################ number_of_models = 1 if use_ensemble == True: number_of_models = 3 if verbose == True: print("White matter hyperintensity: retrieving model weights.") unet_models = list() for i in range(number_of_models): if number_of_channels == 1: weights_file_name = get_pretrained_network( "sysuMediaWmhFlairOnlyModel" + str(i), antsxnet_cache_directory=antsxnet_cache_directory) else: weights_file_name = get_pretrained_network( "sysuMediaWmhFlairT1Model" + str(i), antsxnet_cache_directory=antsxnet_cache_directory) unet_model = create_sysu_media_unet_model_2d( (*image_size, number_of_channels)) unet_loss = binary_dice_coefficient(smoothing_factor=1.) unet_model.compile(optimizer=keras.optimizers.Adam(learning_rate=2e-4), loss=unet_loss) unet_model.load_weights(weights_file_name) unet_models.append(unet_model) ################################ # # Extract slices # ################################ dimensions_to_predict = [2] total_number_of_slices = 0 for d in range(len(dimensions_to_predict)): total_number_of_slices += flair_preprocessed_warped.shape[ dimensions_to_predict[d]] batchX = np.zeros( (total_number_of_slices, *image_size, number_of_channels)) slice_count = 0 for d in range(len(dimensions_to_predict)): number_of_slices = flair_preprocessed_warped.shape[ dimensions_to_predict[d]] if verbose == True: print("Extracting slices for dimension ", dimensions_to_predict[d], ".") for i in range(number_of_slices): flair_slice = pad_or_crop_image_to_size( ants.slice_image(flair_preprocessed_warped, dimensions_to_predict[d], i), image_size) batchX[slice_count, :, :, 0] = flair_slice.numpy() if number_of_channels == 2: t1_slice = pad_or_crop_image_to_size( ants.slice_image(t1_preprocessed_warped, dimensions_to_predict[d], i), image_size) batchX[slice_count, :, :, 1] = t1_slice.numpy() slice_count += 1 ################################ # # Do prediction and then restack into the image # ################################ if verbose == True: print("Prediction.") prediction = unet_models[0].predict(np.transpose(batchX, axes=(0, 2, 1, 3)), verbose=verbose) if number_of_models > 1: for i in range(1, number_of_models, 1): prediction += unet_models[i].predict(np.transpose(batchX, axes=(0, 2, 1, 3)), verbose=verbose) prediction /= number_of_models prediction = np.transpose(prediction, axes=(0, 2, 1, 3)) permutations = list() permutations.append((0, 1, 2)) permutations.append((1, 0, 2)) permutations.append((1, 2, 0)) prediction_image_average = ants.image_clone(flair_preprocessed_warped) * 0 current_start_slice = 0 for d in range(len(dimensions_to_predict)): current_end_slice = current_start_slice + flair_preprocessed_warped.shape[ dimensions_to_predict[d]] which_batch_slices = range(current_start_slice, current_end_slice) prediction_per_dimension = prediction[which_batch_slices, :, :, :] prediction_array = np.transpose(np.squeeze(prediction_per_dimension), permutations[dimensions_to_predict[d]]) prediction_image = ants.copy_image_info( flair_preprocessed_warped, pad_or_crop_image_to_size(ants.from_numpy(prediction_array), flair_preprocessed_warped.shape)) prediction_image_average = prediction_image_average + ( prediction_image - prediction_image_average) / (d + 1) current_start_slice = current_end_slice probability_image = ants.apply_ants_transform_to_image( ants.invert_ants_transform(xfrm), prediction_image_average, flair_preprocessed) probability_image = ants.copy_image_info(flair, probability_image) return (probability_image)
translation = np.asarray(center_of_mass_image) - np.asarray( center_of_mass_template) xfrm = ants.create_ants_transform(transform_type="Euler3DTransform", center=np.asarray(center_of_mass_template), translation=translation) warped_image = ants.apply_ants_transform_to_image(xfrm, image, reorient_template, interpolation='linear') warped_mask = ants.apply_ants_transform_to_image(xfrm, mask, reorient_template, interpolation='linear') warped_mask = ants.threshold_image(warped_mask, 0.4999, 1.0001, 1, 0) warped_mask = ants.iMath(warped_mask, "MD", 3) warped_cropped_image = ants.crop_image(warped_image, warped_mask, 1) original_cropped_size = warped_cropped_image.shape warped_cropped_image = ants.resample_image(warped_cropped_image, resampled_image_size, use_voxels=True) end_time = time.time() elapsed_time = end_time - start_time print(" (elapsed time: ", elapsed_time, " seconds)") batchX = np.expand_dims(warped_cropped_image.numpy(), axis=0) batchX = np.expand_dims(batchX, axis=-1) batchX = (batchX - batchX.mean()) / batchX.std() print("Prediction and decoding") start_time = time.time() predicted_data = unet_model.predict(batchX, verbose=0)