| from pathlib import Path |
| import argparse |
|
|
| import numpy as np |
| from PIL import Image |
| import scipy.ndimage as ndimage |
| import skimage.io as io |
| from skimage.exposure import equalize_adapthist |
| from scipy.interpolate import interp1d |
| from skimage.morphology import disk |
|
|
|
|
|
|
| def crop_center(img, cropx, cropy): |
| y, x = img.shape[0], img.shape[1] |
| startx = x//2-(cropx//2) |
| starty = y//2-(cropy//2) |
| return img[starty:starty+cropy, startx:startx+cropx] |
|
|
|
|
| def to_0_1(img): |
| interp_fun = interp1d([img.min(), img.max()], [0.0, 1.0]) |
| return interp_fun(img) |
|
|
|
|
| def enhance_image(img, mask, int_format=False, disk_size=5): |
| """Enhance an image using the method described in the paper. |
| Args: |
| img (uint8 np.ndarray): Image to enhance |
| mask (np.ndarray): ROI mask of the image to enhance |
| |
| Returns: |
| Enhanced image |
| """ |
| |
| if isinstance(img, str) or isinstance(img, Path): |
| img = io.imread(img)[..., :3] |
| if isinstance(mask, str) or isinstance(mask, Path): |
| mask = io.imread(mask) |
|
|
| if len(img.shape) == 3: |
| if img.shape[2] > 3: |
| img = img[:, :, :3] |
| if len(mask.shape) == 3: |
| mask = np.sum(mask[:, :, :3], axis=2) |
|
|
| img = img / 255 |
| |
| mask = np.where(mask > 0.5, 1, 0) |
|
|
| |
| img_copy = img.copy() |
| |
| zoomed_image = Image.fromarray(np.uint8(img_copy*255)) |
| |
| zoomed_image = zoomed_image.resize( |
| (int(img_copy.shape[1]*1.15), int(img_copy.shape[0]*1.15)), |
| Image.BICUBIC |
| ) |
| |
| zoomed_image = np.array(zoomed_image) |
| |
| zoomed_image = crop_center(zoomed_image, img_copy.shape[1], |
| img_copy.shape[0]) |
| |
| zoomed_image = zoomed_image / 255.0 |
|
|
| |
| kernel = disk(disk_size) |
|
|
| |
| mask = ndimage.binary_erosion(mask, kernel) |
| |
| mask = mask * 1.0 |
|
|
| img_copy[mask < 1.0] = 0.0 |
|
|
| |
| mask = np.stack((mask, mask, mask), axis=2) |
|
|
| composed_image = mask.copy() |
| composed_image[mask == 1.0] = img_copy[mask == 1.0] |
| composed_image[mask < 1.0] = zoomed_image[mask < 1.0] |
|
|
| filtered_image = ndimage.gaussian_filter(composed_image, sigma=(10, 10, 0)) |
|
|
| subtracted_image = composed_image - filtered_image |
| subtracted_image[mask < 1.] = 0. |
|
|
| enhanced_image = subtracted_image/np.std(subtracted_image) |
| enhanced_image = to_0_1(enhanced_image) |
| enhanced_image[mask < 1.] = 0. |
|
|
| mask = mask[:, :, 0] |
|
|
| if int_format: |
| enhanced_image *= 255 |
| enhanced_image = enhanced_image.astype(np.uint8) |
| mask *= 255 |
| mask = mask.astype(np.uint8) |
|
|
| return enhanced_image, mask |
|
|
|
|
| def preprocess_img(img, mask): |
| img_enh, mask_enh = enhance_image(img, mask, int_format=True) |
| img_enh_clahe = equalize_adapthist(img_enh, clip_limit=0.01) |
| return img_enh_clahe, mask_enh |
|
|
|
|
| if __name__ == '__main__': |
| parser = argparse.ArgumentParser(description='Preprocess images and masks.') |
| parser.add_argument( |
| '-c', '--cfp_path', |
| type=str, |
| required=True, |
| help='Path to the images to preprocess', |
| ) |
| parser.add_argument( |
| '-m', '--mask_path', |
| type=str, |
| required=True, |
| help='Path to the masks to preprocess', |
| ) |
| parser.add_argument( |
| '-p', '--out_pre_path', |
| type=str, |
| required=True, |
| help='Path to save the preprocessed images', |
| ) |
| parser.add_argument( |
| '-o', '--out_mask_path', |
| type=str, |
| required=True, |
| help='Path to save the preprocessed masks', |
| ) |
| args = parser.parse_args() |
| cfp_path = Path(args.cfp_path) |
| mask_path = Path(args.mask_path) |
| out_pre_path = Path(args.out_pre_path) |
| out_mask_path = Path(args.out_mask_path) |
| for cfp_fn in sorted(cfp_path.iterdir()): |
| print(cfp_fn) |
| mask_fn = mask_path / cfp_fn.name |
| img_enh_clahe, mask_enh = preprocess_img(cfp_fn, mask_fn) |
| img_enh_clahe = (img_enh_clahe * 255).astype('uint8') |
| mask_enh = (mask_enh > 127).astype('uint8') * 255 |
| out_pre_fn = out_pre_path / cfp_fn.name |
| out_pre_fn.parent.mkdir(parents=True, exist_ok=True) |
| io.imsave(out_pre_fn, img_enh_clahe) |
| out_mask_fn = out_mask_path / cfp_fn.name |
| out_mask_fn.parent.mkdir(parents=True, exist_ok=True) |
| io.imsave(out_mask_fn, mask_enh) |
|
|
|
|