| import sys |
| sys.path.append('../TM2_segmentation') |
|
|
| import os |
| os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE" |
|
|
| import logging |
| import SimpleITK as sitk |
| from scipy.signal import medfilt |
| import numpy as np |
| import nibabel as nib |
| import scipy |
| import skimage |
| import functools |
| from skimage.transform import resize |
| import subprocess |
| import pandas as pd |
| import shutil |
| import itk |
|
|
| |
| def iou(component1, component2): |
| component1 = np.array(component1, dtype=bool) |
| component2 = np.array(component2, dtype=bool) |
|
|
| overlap = component1 * component2 |
| union = component1 + component2 |
|
|
| IOU = overlap.sum()/float(union.sum()) |
| return IOU |
|
|
| |
| def get_id_and_path(row, image_dir, nested = False, no_tms=True): |
| patient_id, image_path, ltm_file, rtm_file = "","","","" |
| if no_tms and row['Ok registered? Y/N'] == "N" : |
| print("skip - bad registration") |
| return "","","","" |
| if "NDAR" in str(row['Filename']) and nested==False and no_tms: |
| patient_id = str(row['Filename']).split("_")[0] |
| else: |
| patient_id = str(row['Filename']).split(".")[0] |
|
|
| path = find_file_in_path(patient_id, os.listdir(image_dir)) |
| |
| if nested: |
| patient_id = patient_id.split("/")[-1] |
| path = patient_id.split("/")[-1] |
| if no_tms==False: |
| path="" |
| |
| scan_folder = image_dir+path |
| patient_id=patient_id.split("/")[-1] |
| |
| for file in os.listdir(scan_folder): |
| t = image_dir+path+"/"+file |
| if "LTM" in file: |
| ltm_file = t |
| elif "RTM" in file: |
| rtm_file = t |
| elif "TM" in file: |
| rtm_file = t |
| ltm_file = t |
| if patient_id in file: |
| image_path = t |
| return patient_id, image_path, ltm_file, rtm_file |
|
|
| |
| def get_id_and_path_not_nested(row, image_dir, masks_dir): |
| patient_id, image_path, tm_file = 0,0,0 |
| if row['Ok registered? Y/N'] == "N": |
| print("skip - bad registration") |
| return 0,0,0,0 |
| if "NDAR" in row['Filename']: |
| patient_id = row['Filename'].split("_")[0] |
| else: |
| patient_id = row['Filename'].split(".")[0] |
|
|
| path = find_file_in_path(patient_id, os.listdir(masks_dir)) |
| if len(path)<3: |
| return 0,0,0,0 |
| scan_folder_masks = masks_dir+path |
|
|
| for file in os.listdir(scan_folder_masks): |
| if "._" in file: |
| continue |
| if "TM" in file: |
| tm_file = masks_dir+path+"/"+file |
| elif ".nii" in file and "TM" not in file: |
| image_path = image_dir+patient_id+".nii" |
|
|
| return patient_id, image_path, tm_file |
|
|
| |
| def crop_center(img,cropx,cropy): |
| y,x = img.shape |
| startx = x//2-(cropx//2) |
| starty = y//2-(cropy//2) |
| return img[starty:starty+cropy,startx:startx+cropx] |
|
|
| |
| def find_file_in_path(name, path): |
| result = [] |
| result = list(filter(lambda x:name in x, path)) |
| if len(result) != 0: |
| for file in result: |
| if "._" in file: |
| continue |
| else: |
| return file |
| else: |
| return "" |
|
|
| |
| def bias_field_correction(img): |
| image = sitk.GetImageFromArray(img) |
| maskImage = sitk.OtsuThreshold(image, 0, 1, 200) |
| corrector = sitk.N4BiasFieldCorrectionImageFilter() |
| numberFittingLevels = 4 |
|
|
| corrector.SetMaximumNumberOfIterations([100] * numberFittingLevels) |
| corrected_image = corrector.Execute(image, maskImage) |
| log_bias_field = corrector.GetLogBiasFieldAsImage(image) |
| corrected_image_full_resolution = image / sitk.Exp(log_bias_field) |
| return sitk.GetArrayFromImage(corrected_image_full_resolution) |
|
|
| def load_nii(path): |
| nii = nib.load(path) |
| return nii.get_fdata(), nii.affine |
|
|
| def save_nii(data, path, affine): |
| nib.save(nib.Nifti1Image(data, affine), path) |
| return |
|
|
| def denoise(volume, kernel_size=3): |
| return medfilt(volume, kernel_size) |
| |
| |
| def apply_window(image, win_centre= 40, win_width= 400): |
| range_bottom = 149 |
| scale = 256 / 256 |
| image = image - range_bottom |
|
|
| image = image * scale |
| image[image < 0] = 0 |
| image[image > 255] = 255 |
| return image |
|
|
| |
| def rescale_intensity(volume, percentils=[0.5, 99.5], bins_num=256): |
| |
| t = skimage.filters.threshold_otsu(volume,nbins=6) |
| volume[volume < t] = 0 |
| |
| obj_volume = volume[np.where(volume > 0)] |
| min_value = np.percentile(obj_volume, percentils[0]) |
| max_value = np.percentile(obj_volume, percentils[1]) |
| if bins_num == 0: |
| obj_volume = (obj_volume - min_value) / (max_value - min_value).astype(np.float32) |
| else: |
| obj_volume = np.round((obj_volume - min_value) / (max_value - min_value) * (bins_num - 1)) |
| obj_volume[np.where(obj_volume < 1)] = 1 |
| obj_volume[np.where(obj_volume > (bins_num - 1))] = bins_num - 1 |
|
|
| volume = volume.astype(obj_volume.dtype) |
| volume[np.where(volume > 0)] = obj_volume |
| return volume |
|
|
| |
| def equalize_hist(volume, bins_num=256): |
| obj_volume = volume[np.where(volume > 0)] |
| hist, bins = np.histogram(obj_volume, bins_num) |
| cdf = hist.cumsum() |
| cdf = (bins_num - 1) * cdf / cdf[-1] |
|
|
| obj_volume = np.round(np.interp(obj_volume, bins[:-1], cdf)).astype(obj_volume.dtype) |
| volume[np.where(volume > 0)] = obj_volume |
| return volume |
|
|
| |
| def enhance(volume, kernel_size=3, |
| percentils=[0.5, 99.5], bins_num=256, eh=True): |
| try: |
| volume = bias_field_correction(volume) |
| volume = denoise(volume, kernel_size) |
| volume = rescale_intensity(volume, percentils, bins_num) |
| if eh: |
| volume = equalize_hist(volume, bins_num) |
| return volume |
| except RuntimeError: |
| logging.warning('Failed enchancing') |
|
|
| |
| def enhance_noN4(volume, kernel_size=3, |
| percentils=[0.5, 99.5], bins_num=256, eh=True): |
| try: |
| |
| volume = denoise(volume, kernel_size) |
| |
| volume = rescale_intensity(volume, percentils, bins_num) |
| |
| if eh: |
| volume = equalize_hist(volume, bins_num) |
| return volume |
| except RuntimeError: |
| logging.warning('Failed enchancing') |
|
|
| |
| def get_resampled_sitk(data_sitk,target_spacing): |
| new_spacing = target_spacing |
|
|
| orig_spacing = data_sitk.GetSpacing() |
| orig_size = data_sitk.GetSize() |
|
|
| new_size = [int(orig_size[0] * orig_spacing[0] / new_spacing[0]), |
| int(orig_size[1] * orig_spacing[1] / new_spacing[1]), |
| int(orig_size[2] * orig_spacing[2] / new_spacing[2])] |
|
|
| res_filter = sitk.ResampleImageFilter() |
| img_sitk = res_filter.Execute(data_sitk, |
| new_size, |
| sitk.Transform(), |
| sitk.sitkLinear, |
| data_sitk.GetOrigin(), |
| new_spacing, |
| data_sitk.GetDirection(), |
| 0, |
| data_sitk.GetPixelIDValue()) |
|
|
| return img_sitk |
|
|
| |
| def nrrd_to_nifty(nrrd_file): |
| _nrrd = nrrd.read(nrrd_file) |
| data_f = _nrrd[0] |
| header = _nrrd[1] |
| return np.asarray(data_f), header |
|
|
| |
| def crop_brain(var_img, mni_img): |
| |
| inverted_mask = np.invert(mni_img.astype(bool)).astype(float) |
| mask_data = inverted_mask * var_img |
| return mask_data |
|
|
| |
| def brain_norm_masked(mask_data, brain_data, to_save=False): |
| masked = crop_brain(brain_data, mask_data) |
| enhanced = enhance(masked) |
| return enhanced |
|
|
| |
| def enhance_and_debias_all_in_path(image_dir='data/mni_templates_BK/',path_to='data/denoised_mris/',\ |
| input_annotation_file = 'data/all_metadata.csv'): |
|
|
| df = pd.read_csv(input_annotation_file,header=0) |
| df=df[df['Ok registered? Y/N']=='Y'].reset_index() |
| |
| for idx in range(0, 1): |
| print(idx) |
| row = df.iloc[idx] |
| patient_id, image_path, tm_file, _ = get_id_and_path(row, image_dir) |
| print(patient_id, image_path, tm_file) |
| image_sitk = sitk.ReadImage(image_path) |
| image_array = sitk.GetArrayFromImage(image_sitk) |
| image_array = enhance(image_array) |
| image3 = sitk.GetImageFromArray(image_array) |
| sitk.WriteImage(image3,path_to+patient_id+'.nii') |
| return |
|
|
| |
| def z_enhance_and_debias_all_in_path(image_dir='data/mni_templates_BK/',path_to='data/z_scored_mris/',\ |
| input_annotation_file = 'data/all_metadata.csv', for_training=True, annotations=True): |
| df = pd.read_csv(input_annotation_file,header=0) |
| |
| if for_training: |
| df=df[df['Ok registered? Y/N']=='Y'].reset_index() |
| print(df.shape[0]) |
| |
| for idx in range(0, df.shape[0]): |
| print(idx) |
| row = df.iloc[idx] |
| patient_id, image_path, tm_file, _ = get_id_and_path(row, image_dir, nested=False, no_tms=for_training) |
| print(patient_id, len(image_path), tm_file, path_to) |
| if not os.path.isdir(path_to+"no_z"): |
| os.mkdir(path_to+"no_z") |
| if not os.path.isdir(path_to+"z"): |
| os.mkdir(path_to+"z") |
| |
| if len(image_path)>3: |
| image_sitk = sitk.ReadImage(image_path) |
| image_array = sitk.GetArrayFromImage(image_sitk) |
| print(len(image_array)) |
| try: |
| image_array = enhance_noN4(image_array) |
| image3 = sitk.GetImageFromArray(image_array) |
| sitk.WriteImage(image3,path_to+"no_z/"+patient_id+'.nii') |
| os.mkdir(path_to+"z/"+patient_id) |
| if annotations: |
| shutil.copyfile(tm_file, path_to+"z/"+patient_id+"/TM.nii.gz") |
| duck_line = "zscore-normalize "+path_to+"no_z/"+patient_id+".nii -o "+path_to+"z/"+patient_id +"/"+patient_id+'.nii' |
| subprocess.getoutput(duck_line) |
| except: |
| continue |
|
|
| |
| def closest_value(input_list, input_value): |
| arr = np.asarray(input_list) |
| i = (np.abs(arr - input_value)).argmin() |
| return arr[i], i |
|
|
| |
| def find_centile(input_tmt, age, df): |
| |
| val,i=closest_value(df['x'],age) |
| |
| centile = 'out of range' |
| if input_tmt<df.iloc[i]['X3']: |
| centile ='< 3' |
| if df.iloc[i]['X3']<=input_tmt<df.iloc[i]['X10']: |
| centile ='3-10' |
| if df.iloc[i]['X10']<=input_tmt<df.iloc[i]['X25']: |
| centile ='10-25' |
| if df.iloc[i]['X25']<=input_tmt<df.iloc[i]['X50']: |
| centile ='25-50' |
| if df.iloc[i]['X50']<=input_tmt<df.iloc[i]['X75']: |
| centile ='50-75' |
| if df.iloc[i]['X75']<=input_tmt<df.iloc[i]['X90']: |
| centile ='75-90' |
| if df.iloc[i]['X90']<=input_tmt<df.iloc[i]['X97']: |
| centile ='90-97' |
| if input_tmt>df.iloc[i]['X97']: |
| centile ='97>' |
| |
| return centile |
|
|
| |
| def find_exact_percentile_return_number(input_tmt, age, df): |
| |
| val,i=closest_value(df['x'],age) |
| |
| mu = df.iloc[i]['mu'] |
| sigma = df.iloc[i]['sigma'] |
| nu = df.iloc[i]['nu'] |
| |
| |
| if nu!=0: |
| z = ((input_tmt/mu)**(nu)-1)/(nu*sigma) |
| else: |
| z = 1/sigma * math.log(input_tmt/mu) |
| percentile = scipy.stats.norm.cdf(z) |
| return round(percentile*100,2) |
|
|
| |
| def add_median_labels(ax, fmt='.1f'): |
| lines = ax.get_lines() |
| boxes = [c for c in ax.get_children() if type(c).__name__ == 'PathPatch'] |
| lines_per_box = int(len(lines) / len(boxes)) |
| for median in lines[4:len(lines):lines_per_box]: |
| x, y = (data.mean() for data in median.get_data()) |
| |
| value = x if (median.get_xdata()[1] - median.get_xdata()[0]) == 0 else y |
| text = ax.text(x, y, f'{value:{fmt}}', ha='center', va='center', |
| fontweight='ultralight', color='gray') |
| |
| text.set_path_effects([ |
| path_effects.Stroke(linewidth=3, foreground=median.get_color()), |
| path_effects.Normal(), |
| ]) |
|
|
| |
| def register_to_template(input_image_path, output_path, fixed_image_path,create_subfolder=True): |
| fixed_image = itk.imread(fixed_image_path, itk.F) |
|
|
| |
| parameter_object = itk.ParameterObject.New() |
| parameter_object.AddParameterFile('data/golden_image/mni_templates/Parameters_Rigid.txt') |
|
|
| if "nii" in input_image_path and "._" not in input_image_path: |
| print(input_image_path) |
|
|
| |
| try: |
| moving_image = itk.imread(input_image_path, itk.F) |
| result_image, result_transform_parameters = itk.elastix_registration_method( |
| fixed_image, moving_image, |
| parameter_object=parameter_object, |
| log_to_console=False) |
| image_id = input_image_path.split("/")[-1] |
| |
| if create_subfolder: |
| new_dir = output_path+image_id.split(".")[0] |
| if not os.path.exists(new_dir): |
| os.mkdir(new_dir) |
| itk.imwrite(result_image, new_dir+"/"+image_id) |
| else: |
| itk.imwrite(result_image, output_path+"/"+image_id) |
| |
| print("Registered ", image_id) |
| except: |
| print("Cannot transform", input_image_path.split("/")[-1]) |
| |
| if __name__=="__main__": |
| |
| ''' |
| z_enhance_and_debias_all_in_path(image_dir='data/mni_templates_BK/', |
| path_to='data/z_scored_mris/z_with_pseudo/',\ |
| input_annotation_file = 'data/all_metadata.csv') |
| |
| z_enhance_and_debias_all_in_path(image_dir='data/curated_test/reg_tm_not_corrected/', |
| path_to='data/curated_test/final_test/', |
| input_annotation_file = 'data/curated_test/reg_tm_not_corrected/Dataset_test_rescaled.csv', |
| for_training=True) |
| # all the datasets |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/registered_not_ench/', |
| path_to='data/t1_mris/registered/', |
| input_annotation_file = 'data/Dataset_t1_healthy_raw.csv', |
| for_training=False,annotations=False) |
| |
| #ping |
| # z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/pings_registered/', |
| path_to='data/t1_mris/pings_ench_reg/', |
| input_annotation_file = 'data/Dataset_ping.csv', |
| for_training=False, annotations=False) |
| # pixar |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/pixar/', |
| path_to='data/t1_mris/pixar_ench/', |
| input_annotation_file = 'data/Dataset_pixar.csv', |
| for_training=False, annotations=False) |
| #abide |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/abide_registered/', |
| path_to='data/t1_mris/abide_ench_reg/', |
| input_annotation_file = "data/Dataset_abide.csv", |
| for_training=False, annotations=False) |
| |
| # calgary |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/calgary_reg/', |
| path_to='data/t1_mris/calgary_reg_ench/', |
| input_annotation_file = "data/Dataset_calgary.csv", |
| for_training=False, annotations=False) |
| |
| # aomic replace header with ,AGE_M,SEX,SCAN_PATH,Filename,dataset |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/aomic_reg/', |
| path_to='data/t1_mris/aomic_reg_ench/', |
| input_annotation_file = "data/Dataset_aomic.csv", |
| for_training=False, annotations=False) |
| |
| # NIHM replace header with ,AGE_M,SEX,SCAN_PATH,Filename,dataset |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/nihm_reg/', |
| path_to='data/t1_mris/nihm_ench_reg/', |
| input_annotation_file = "data/Dataset_nihm.csv", |
| for_training=False, annotations=False) |
| |
| # ICBM replace header with ,AGE_M,SEX,SCAN_PATH,Filename,dataset |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/icbm_reg/', |
| path_to='data/t1_mris/icbm_ench_reg/', |
| input_annotation_file = "data/Dataset_icbm.csv", |
| for_training=False, annotations=False) |
| |
| # SALD |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/sald_reg/', |
| path_to='data/t1_mris/sald_reg_ench/', |
| input_annotation_file = "data/Dataset_sald.csv", |
| for_training=False, annotations=False) |
| |
| ## NYU |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/nyu_reg/', |
| path_to='data/t1_mris/nyu_reg_ench/', |
| input_annotation_file = "data/Dataset_nyu.csv", |
| for_training=False, annotations=False) |
| ## NAH |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/healthy_adults_nihm/', |
| path_to='data/t1_mris/healthy_adults_nihm_reg_ench/', |
| input_annotation_file = "data/Dataset_healthy_adults_nihm.csv", |
| for_training=False, annotations=False) |
| ## Petfrog |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/petfrog_reg/', |
| path_to='data/t1_mris/petfrog_reg_ench/', |
| input_annotation_file = "data/Dataset_petfrog.csv", |
| for_training=False, annotations=False) |
| ## CBTN |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/cbtn_reg/', |
| path_to='data/t1_mris/cbtn_reg_ench/', |
| input_annotation_file = "data/Dataset_cbtn.csv", |
| for_training=False, annotations=False) |
| ## DMG |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/dmg_reg/', |
| path_to='data/t1_mris/dmg_reg_ench/', |
| input_annotation_file = "data/Dataset_dmg.csv", |
| for_training=False, annotations=False) |
| ## BCH |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/bch_reg/', |
| path_to='data/t1_mris/bch_reg_ench/', |
| input_annotation_file = "data/Dataset_bch.csv", |
| for_training=False, annotations=False) |
| ## BCH long |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/bch_long_reg/', |
| path_to='data/t1_mris/bch_long_reg_ench/', |
| input_annotation_file = "data/Dataset_bch_long.csv", |
| for_training=False, annotations=False) |
| ## 28 |
| z_enhance_and_debias_all_in_path(image_dir='data/t1_mris/uscf_reg/', |
| path_to='data/t1_mris/uscf_reg_ench/', |
| input_annotation_file = "data/Dataset_ucsf.csv", |
| for_training=False, annotations=False)''' |
| |
| z_enhance_and_debias_all_in_path(image_dir='data/bch_long_pre_test/reg/', |
| path_to='data/bch_long_pre_test/reg_ench/', |
| input_annotation_file = "data/Dataset_bch_long_pre_test.csv", |
| for_training=False, annotations=False) |
| |
| |