def main(args): target_list = list_files(args.target_dir, 'png') for j, target_fname in enumerate(target_list): target_ffname = os.path.splitext(os.path.basename(target_fname))[0] print("Target: " + target_ffname) target_filepath = os.path.join(args.target_dir, target_fname) target = staintools.read_image(target_filepath) target = staintools.LuminosityStandardizer.standardize(target) normalizer = staintools.StainNormalizer(method='vahadane') normalizer.fit(target) output_dir_target = os.path.join(args.output_dir, target_ffname) mkdir_if_nonexist(output_dir_target) image_list = list_files(args.input_dir, args.ext) for i, image_fname in enumerate(image_list): image_ffname = os.path.splitext(os.path.basename(image_fname))[0] print("Normalizing: " + image_fname) image_filepath = os.path.join(args.input_dir, image_fname) to_transform = staintools.read_image(image_filepath) to_transform = staintools.LuminosityStandardizer.standardize( to_transform) transformed = normalizer.transform(to_transform) transformed_BGR = cv2.cvtColor(transformed, cv2.COLOR_RGB2BGR) cv2.imwrite(os.path.join(output_dir_target, image_ffname + '.png'), transformed_BGR) return 0
def color_normalization(template_image_path, color_norm_method): """ The function put all the color normalization methods together. :param template_image_path: the template image for normalization :type template_image_path: string :param color_norm_method: the method for color normalization :type color_norm_method: string :return: color_normalizer. It is the initialized object for the actual normalization. :rtype: object """ template_image = staintools.read_image(template_image_path) standardizer = staintools.LuminosityStandardizer.standardize( template_image) if color_norm_method == 'Reinhard': color_normalizer = stainNorm_Reinhard.Normalizer() color_normalizer.fit(standardizer) elif color_norm_method == 'Macenko': color_normalizer = stainNorm_Macenko.Normalizer() color_normalizer.fit(standardizer) elif color_norm_method == 'Vahadane': color_normalizer = staintools.StainNormalizer(method='vahadane') color_normalizer.fit(standardizer) return color_normalizer
def preprocess_tcga_crc_heslides(folder, out_dir, normalize_target, thread = 1, blank_ratio = 0.5, tile_size = 224, overlapping = 0.25, augment = 0, level = 0): """ Split the entire H&E slides into small effective tiles Parameter: 1. folder: name of the folder where the targer image exists. 2. out_dir: name of the output folder. 3. normalize_target: reference image used to normalize the data 4. thread: number of threads 4. blank_ratio: ratio of the blank area (R > 220). 5. tile_size: size of each tile. 6. overlapping: step size Precondition: 1. folder, fileNames and out_dir are UNIX style """ target = staintools.read_image(normalize_target) normalizer = staintools.StainNormalizer(method='vahadane') normalizer.fit(target) #for folder1 in os.listdir(folder): files = [f for f in os.listdir(folder) if os.path.isfile(folder + "/" + f)] #for file2 in files: # output_dir = split_norm(folder, file2, out_dir, normalizer) if thread > 1: Parallel(thread)(delayed(split_norm)(folder, file2, out_dir, normalizer, overlapping, blank_ratio, tile_size, augment, level, thread) for file2 in files) else: for file2 in files: split_norm(folder, file2, out_dir, normalizer, overlapping, blank_ratio, tile_size, augment, level, thread)
def resize_image(image): resized_image = cv2.resize(image, (128,128), interpolation = cv2.INTER_AREA) #Resize all the images to 128X128 dimensions target = staintools.LuminosityStandardizer.standardize(resized_image) normalizer = staintools.StainNormalizer(method='vahadane') normalizer.fit(target) transformed = normalizer.transform(target) return transformed
def stain_normilize(img_dir, save_dir, stain_norm_target, norm_brightness=False): file_list = glob.glob(os.path.join(img_dir, '*.png')) file_list.sort() if norm_brightness: standardizer = staintools.LuminosityStandardizer() stain_normalizer = staintools.StainNormalizer(method='vahadane') # dict of paths to target image and dir code to make output folder # {'/data/TCGA-21-5784-01Z-00-DX1.tif' : '5784'} # stain_norm_targets = {k : v for k, v in zip(glob.glob(os.path.join(targets_dir, '*.*')), range(len(glob.glob(os.path.join(targets_dir, '*.*')))))} # stain_norm_target = {target : '1'} target_img = cv2.imread(stain_norm_target) target_img = cv2.cvtColor(target_img, cv2.COLOR_BGR2RGB) if norm_brightness: target_img = standardizer.standardize(target_img) stain_normalizer.fit(target_img) norm_dir = save_dir rm_n_mkdir(norm_dir) for img_path in file_list: filename = os.path.basename(img_path) basename = filename.split('.')[0] img = cv2.imread(img_path) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) if norm_brightness: img = standardizer.standardize(img) img = stain_normalizer.transform(img) img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) cv2.imwrite(os.path.join(norm_dir, '{}.png'.format(basename)), img) print(f"Saved {os.path.join(norm_dir, '{}.png'.format(basename))}.")
def stainAug(image_fname, ext, target_dir, stainAug_dir, output_stain_augmentation=False): stain_aug_list = [] image_ffname = os.path.splitext(os.path.basename(image_fname))[0] to_transform = staintools.read_image(image_fname) to_transform = staintools.LuminosityStandardizer.standardize(to_transform) orignal_image = cv2.imread(image_fname, -1) stain_aug_list.append(orignal_image) if output_stain_augmentation: # Write original images to png files cv2.imwrite(os.path.join(stainAug_dir, image_ffname+'_0.png'), orignal_image) print("Normalizing: " + image_ffname) # Get stain normalization target file list target_list = list_files(target_dir, 'png') target_list = sorted(target_list, key = lambda x: int(x[:-9])) for j, target_fname in enumerate(target_list): target_ffname = os.path.splitext(os.path.basename(target_fname))[0] print("Target: " + target_ffname) target_filepath = os.path.join(target_dir, target_fname) target = staintools.read_image(target_filepath) target = staintools.LuminosityStandardizer.standardize(target) normalizer = staintools.StainNormalizer(method='vahadane') normalizer.fit(target) transformed = normalizer.transform(to_transform) transformed_BGR = cv2.cvtColor(transformed, cv2.COLOR_RGB2BGR) stain_aug_list.append(transformed_BGR) if output_stain_augmentation: # Write stain normalized images to png files cv2.imwrite(os.path.join(stainAug_dir, image_ffname+'_'+str(j+1)+'.png'), transformed_BGR) return stain_aug_list
def normalization(img, sttd): img = np.array(img)[:, :, :3] img = staintools.LuminosityStandardizer.standardize(img) normalizer = staintools.StainNormalizer(method='vahadane') normalizer.fit(sttd) img = normalizer.transform(img) img = Image.fromarray(img.astype('uint8'), 'RGB') return img
def stain_norm(std_img, f_p, dst): standardizer = staintools.BrightnessStandardizer() i_std = staintools.read_image(std_img) stain_normalizer = staintools.StainNormalizer(method='vahadane') i_standard = standardizer.transform(i_std) stain_normalizer.fit(i_standard) os.makedirs(dst, exist_ok=True) for f in os.listdir(f_p): img = staintools.read_image(os.path.join(f_p, f)) i_normalized = stain_normalizer.transform(standardizer.transform(img)) cv2.imwrite(os.path.join(dst, os.path.basename(f)), i_normalized)
def normalization(img, sttd): img = np.array(img)[:, :, :3] try: img = staintools.LuminosityStandardizer.standardize(img) normalizer = staintools.StainNormalizer(method='vahadane') normalizer.fit(sttd) img = normalizer.transform(img) except Exception as err: print(type(err)) print(err) pass img = Image.fromarray(img.astype('uint8'), 'RGB') return img
def transform(image, target_im): # Read data target = staintools.read_image(image) to_transform = staintools.read_image(target_im) # Standardize brightness (This step is optional but can improve the tissue mask calculation) standardizer = staintools.BrightnessStandardizer() target = standardizer.transform(target) to_transform = standardizer.transform(to_transform) # Stain normalize normalizer = staintools.StainNormalizer(method='vahadane') normalizer.fit(target) transformed = normalizer.transform(to_transform) return transformed
def test_traditional_fps(source_img, ref_img, method, n_iters): ref_img = np.array(ref_img) source_img = np.array(ref_img) if method == "reinhard": normalizer = staintools.ReinhardColorNormalizer() else: normalizer = staintools.StainNormalizer(method=method) normalizer.fit(np.array(ref_img)) start = time.time() for i in tqdm(range(n_iters)): try: img1_normalized = normalizer.transform(source_img) except: pass need_time = time.time() - start print(method, "FPS is ", n_iters / need_time)
def staintransfer(target, patch_dict): ''' ref: https://github.com/Peter554/StainTools Used staintools python package and vahadane method ''' print("Transferring target stain to image patches...") target = target.convert('RGB') target = np.array(target) # convert to opencv RGB target = staintools.LuminosityStandardizer.standardize( target) # standardize brightness # Stain normalize normalizer = staintools.StainNormalizer(method='vahadane') normalizer.fit(target) transformed_list = [] for key, image in patch_dict.items(): image = image.convert('RGB') image = np.array(image) # convert to opencv RGB try: image = staintools.LuminosityStandardizer.standardize( image) # standardize brightness image_gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY) if np.mean(image_gray) >= 249.0: # skip mostly white images transformed = image # check if image has tissues (removed pink patches) if not keep_tile(image, 0.05): transformed = image else: transformed = normalizer.transform(image) # if transformed image is black,replace with original image if np.mean(transformed) == 0.0: transformed = image except staintools.miscellaneous.exceptions.TissueMaskException: print('Exception: ' + key) transformed_list.append(Image.fromarray(image)) continue transformed_list.append(Image.fromarray(transformed)) return transformed_list
def traditional_methods(opt): image_source = list_file_tree(opt.source_dir, "png") image_target = list_file_tree(opt.gt_dir, "png") image_source.sort() image_target.sort() if opt.method == "reinhard": normalizer = staintools.ReinhardColorNormalizer() else: normalizer = staintools.StainNormalizer(method=opt.method) if opt.random_target: num = random.randint(0, len(image_target) - 1) save_path = os.path.join(opt.save_root, opt.method + "_random") os.makedirs(save_path, exist_ok=True) print("target choose:", image_target[num]) target = staintools.read_image(image_target[num]) normalizer.fit(target) for source in tqdm(image_source): img = staintools.read_image(source) filename = os.path.split(source)[1] try: img_normalized = normalizer.transform(img) imageio.imwrite( os.path.join(save_path, filename[:-4] + ".png"), img_normalized) except: print("error in ", source) else: save_path = os.path.join(opt.save_root, opt.method + "_matched") os.makedirs(save_path, exist_ok=True) for source, target in tqdm(zip(image_source, image_target)): img1 = staintools.read_image(source) img2 = staintools.read_image(target) filename = os.path.split(source)[1] try: normalizer.fit(img2) img1_normalized = normalizer.transform(img1) imageio.imwrite( os.path.join(save_path, filename[:-4] + ".png"), img1_normalized) except: print("error in ", source) return save_path
def color_normalization(template_image_path, color_norm_method): """ The function put all the color normalization methods together. :param string template_image_path: the path of the image used as a template :param string color_norm_method: one of the three methods: vahadane, macenko, reinhard. :return object """ template_image = staintools.read_image(template_image_path) standardizer = staintools.LuminosityStandardizer.standardize( template_image) if color_norm_method == 'Reinhard': color_normalizer = stainNorm_Reinhard.Normalizer() color_normalizer.fit(standardizer) elif color_norm_method == 'Macenko': color_normalizer = stainNorm_Macenko.Normalizer() color_normalizer.fit(standardizer) elif color_norm_method == 'Vahadane': color_normalizer = staintools.StainNormalizer(method='vahadane') color_normalizer.fit(standardizer) return color_normalizer
def __call__(self, img): if random.random() < self.prob: target = staintools.read_image(self.path2ref) to_transform = staintools.LuminosityStandardizer.standardize( np.array(img).astype('uint8')) target = staintools.LuminosityStandardizer.standardize(target) to_transform = staintools.LuminosityStandardizer.standardize( to_transform) normalizer = staintools.StainNormalizer(method='vahadane') normalizer.fit(target) im_nmzd = normalizer.transform(to_transform) stainColorMap = { 'hematoxylin': [0.65, 0.70, 0.29], 'eosin': [0.07, 0.99, 0.11], 'dab': [0.27, 0.57, 0.78], 'null': [0.0, 0.0, 0.0] } stain_1 = 'hematoxylin' # nuclei stain stain_2 = 'eosin' # cytoplasm stain stain_3 = 'null' # set to null of input contains only two stains W = np.array([ stainColorMap[stain_1], stainColorMap[stain_2], stainColorMap[stain_3] ]).T im_stains = htk.preprocessing.color_deconvolution.color_deconvolution( im_nmzd, W).Stains a = htk.filters.edge.gaussian_grad(im_stains[:, :, 0], sigma=0.16) b = ((a.dx + (a.dx.max() - a.dx.min())) / (a.dx.max() - a.dx.min()) * 255.).astype('uint8') im_stains[:, :, 2] = b.astype('uint8') c = Image.fromarray(im_stains.astype('uint8')) # clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) # b_clahe = clahe.apply(b) # Image.fromarray(b_clahe.astype('uint8')) # c = ((b_clahe>180)*255).astype('uint8') # c = Image.fromarray(c.astype('uint8')) return c else: return img
from statistics import median #2. GENERATE LISTS AND NAMES ###GENERATE LIST OF MODELS (if several models are tested) model_names = sorted(os.listdir(model_dir)) ###MODEL PATCH SIZES: define the patch size to use within models #here for example two models in list, each working with 350px patches m_p_s_list = [350, 350] #3. INITIALIZE STAIN NORMALIZER #Standartization image st = staintools.read_image('standard_he_stain_small.jpg') #Inititate Brightness Standardizer standardizer = staintools.BrightnessStandardizer() #Inititate StainNormalizer "macenko" stain_norm = staintools.StainNormalizer(method='macenko') #Read Hematoxylin/Eosin staining schema from Standartization image stain_norm.fit(st) #4. FUNCTIONS #Implementation of the Strategy C8 (derivates of the main image, s. Methods) #as a function #As input: native version of the patch def gateway_median(patch): #native version of the patch (base) base = patch #1 #rotation derivates r90 = patch.rotate(90) #2 r180 = patch.rotate(180) #3 r270 = patch.rotate(270) #4
i3 = staintools.LuminosityStandardizer.standardize(i3) i4 = staintools.LuminosityStandardizer.standardize(i4) i5 = staintools.LuminosityStandardizer.standardize(i5) # Plot images = [i1, i2, i3, i4, i5] titles = ["Target standardized"] + ["Original standardized"] * 4 staintools.plot_image_list(images, width=5, title_list=titles, \ save_name=RESULTS_DIR + 'original-images-standardized.png', show=0) # =================== # Stain normalization # =================== # Normalize to stain of first image normalizer = staintools.StainNormalizer(method=METHOD) normalizer.fit(i1) i2_normalized = normalizer.transform(i2) i3_normalized = normalizer.transform(i3) i4_normalized = normalizer.transform(i4) i5_normalized = normalizer.transform(i5) # Plot images = [i1, i2_normalized, i3_normalized, i4_normalized, i5_normalized] titles = ["Target"] + ["Stain normalized"] * 4 staintools.plot_image_list(images, width=5, title_list=titles, \ save_name=RESULTS_DIR + 'stain-normalized-images.png', show=0) # ================== # Stain augmentation # ==================
def setup_standardizer(self): img = np.array(Image.open(self.img_files[1]).convert("RGB")) self.normalizer = staintools.StainNormalizer(method='macenko') self.normalizer.fit(img)
def __init__(self, target_fname, method): target = staintools.read_image(target_fname) self.normalizer = staintools.StainNormalizer(method=method) self.normalizer.fit(target)
def build_normalizer(): target = staintools.read_image('./Tissue/TCGA-G9-6356-01Z-00-DX1.tif') target = staintools.LuminosityStandardizer.standardize(target) normalizer = staintools.StainNormalizer(method='vahadane') normalizer.fit(target) return normalizer
#cropped_binary = rgb_binary[x:(x+dx), y:(y+dy)] cropped_mask = mask[x:(x + dx), y:(y + dy)] return (cropped_img, cropped_mask, index) crop_size2 = [224, 224] i = 0 while i < len(tumor_paths): tumor_path = tumor_paths[i] mask_path = osp.join( mask_paths, osp.basename(tumor_paths[i].replace('.png', '_mask.png'))) #image = plt.imread(tumor_path) imgmask = io.imread(mask_path) stain_normalizer = staintools.StainNormalizer(method='vahadane') imagest = staintools.read_image("/home/wli/Downloads/test/tumor_st.png") img = staintools.read_image(tumor_path) standardizer = staintools.BrightnessStandardizer() imagest_standard = standardizer.transform(imagest) img_standard = standardizer.transform(img) stain_normalizer.fit(imagest_standard) img_norm = stain_normalizer.transform(img_standard) imageroted1 = i1_flip = np.fliplr(img_norm) maskroted1 = i1_flip = np.fliplr(imgmask) imageroted2 = np.rot90(img_norm, 1) imageroted3 = np.rot90(img_norm, 2) imageroted4 = np.rot90(img_norm, 3)
def stain_norm_func(target_image_path): target = staintools.read_image(target_image_path) target = staintools.LuminosityStandardizer.standardize(target) normalizer = staintools.StainNormalizer(method='vahadane') normalizer.fit(target) return normalizer
def gen_imgs(samples, crop_size, batch_size, type, shuffle=True, color_norm=False, target="./data/svs_patches/01_01_0091_12800_22528.png"): ''' :param samples: a dataframe which contains the top left coordinates of all patches which contain at least 50% tissue from all images :param batch_size: an int stands for size of the batch :param shuffle: an option whether shuffle samples :param color_norm: an options whether do color normalization :param target: the path of the base image to do color normalization :return: np.arrary of X_train and y_train ''' save_svs_patches = './data/svs_patches' save_patches = './data/' + type + '_patches' num_samples = len(samples) while 1: if shuffle: samples = samples.sample(frac=1) # select a sub-dataframe with size of batch size for offset in range(0, num_samples, batch_size): batch_samples = samples.iloc[offset:offset + batch_size] images = [] masks = [] id_list = list(batch_samples['id']) x_list = list(batch_samples['x']) y_list = list(batch_samples['y']) for i in range(batch_size): a = id_list[i] print('********** Crop in ' + str(a) + ' **********') x = int(x_list[i]) y = int(y_list[i]) print(str(x + 512) + '.....' + str(y + 512)) slide_patch, mask_patch = crop(a, (x, y), crop_size, type)[0:2] # color normalization if color_norm: target = staintools.read_image(target) target = staintools.LuminosityStandardizer.standardize( target) slide_patch = staintools.LuminosityStandardizer.standardize( slide_patch) normalizer = staintools.StainNormalizer(method='vahadane') normalizer.fit(target) slide_patch = normalizer.transform(slide_patch) # save patches if not os.path.exists(save_svs_patches): os.mkdir(save_svs_patches) imsave( osp.join(save_svs_patches, str(a) + '_' + str(x) + '_' + str(y) + '.png'), slide_patch) if not os.path.exists(save_patches): os.mkdir(save_patches) imsave( osp.join( save_patches, str(a) + '_' + str(x) + '_' + str(y) + '_' + type + '.png'), mask_patch) images.append(slide_patch) masks.append(mask_patch) batch_samples = pd.DataFrame(batch_samples) X_train = np.array(images) y_train = np.array(masks) print(np.shape(y_train)) y_train = to_categorical(y_train, num_classes=2).reshape( y_train.shape[0], 512, 512, 2) yield X_train, y_train
def get_stain_normalizer(path='/path/to/reference/image', method='macenko'): target = staintools.read_image(path) target = staintools.LuminosityStandardizer.standardize(target) normalizer = staintools.StainNormalizer(method=method) normalizer.fit(target) return normalizer
def gen_imgs_random(id_list, crop_size, batch_size, type, color_norm=False, target="./data/svs_patches/01_01_0091_12800_22528.png"): ''' :param id_list: a list contains all images ids, all id has the following format: 01_01_0083 :param batch_size: an int stands for size of the batch :param crop_size: a tuple stands for the size for each patch :param color_norm: an options whether do the color normalization :param target: the path of the base image to do color normalization :return: np.arrary of X_train and y_train ''' save_svs_patches = './data/svs_patches_random' save_mask_patches = './data/' + str(type) + '_patches_random' while 1: images = [] masks = [] if not os.path.exists(save_svs_patches): os.mkdir(save_svs_patches) if not os.path.exists(save_mask_patches): os.mkdir(save_mask_patches) # produce a sample with a fit batch size counter = 0 while counter < batch_size: img_id = random.choice(id_list) slide_path = './data/OriginalImage/' + str(img_id) + '.svs' if not os.path.exists(slide_path): slide_path = './data/OriginalImage/' + str(img_id) + '.SVS' slide = openslide.open_slide(slide_path) mask_path = './data/' + type.capitalize() + 'Mask/' + str( img_id) + '_' + type + '.tif' mask = io.imread(mask_path) # inisilize the top left coordinate for each patch shape = np.shape(mask) start_x = np.random.randint(shape[1] - crop_size[1]) start_y = np.random.randint(shape[0] - crop_size[0]) # if the patch is already cropped, drop this patch slide_patch_save_path = osp.join( save_svs_patches, str(img_id) + '_' + str(start_x) + '_' + str(start_y) + '.png') if not os.path.exists(slide_patch_save_path): croped_slide_img = slide.read_region((start_x, start_y), 0, crop_size) croped_slide_img = np.array(croped_slide_img) ''' # convert the patch from RGBA to grey scale in order to drop the patch which contains much backgrpound img_grey = cv2.cvtColor(croped_slide_img, cv2.COLOR_RGBA2GRAY) if len(np.unique(img_grey)) != 1: img_grey = np.array(img_grey) threshold = threshold_otsu(img_grey) # drop the patch where tissue is less than 50% if np.sum(img_grey < threshold) > 0.5 * crop_size[0] * crop_size[1]: ''' # if option of color normalization is true, do color normalization if color_norm: target = staintools.read_image(target) target = staintools.LuminosityStandardizer.standardize( target) croped_slide_img = staintools.LuminosityStandardizer.standardize( croped_slide_img) normalizer = staintools.StainNormalizer(method='vahadane') normalizer.fit(target) croped_slide_img = normalizer.transform(croped_slide_img) # save patches croped_mask_img = mask[start_y:start_y + crop_size[0], start_x:start_x + crop_size[1]] croped_mask_img_2 = croped_mask_img * 255 imsave(slide_patch_save_path, croped_slide_img) imsave( osp.join( save_mask_patches, str(img_id) + '_' + str(start_x) + '_' + str(start_y) + '_' + type + '.png'), croped_mask_img_2) images.append(croped_slide_img) masks.append(croped_mask_img) X_train = np.array(images) y_train = np.array(masks) y_train = to_categorical(y_train, num_classes=2).reshape( y_train.shape[0], crop_size[0], crop_size[1], 2) counter += 1 yield X_train, y_train