from pathlib import Path from typing import Any, Union import numpy as np import cv2 from PIL import Image, ImageEnhance def load_image(file_name, path_to_images=None, rgb: bool = True): path = ( file_name if isinstance(file_name, Path) is True else path_to_images.joinpath(file_name) ) try: img = cv2.imread(str(path)) if rgb is True: img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) except Exception as e: print(file_name) return img def to_pil(image): return Image.fromarray(image) def to_cv2(image): return np.array(image) def enhance_pil_image( image, color=1, brightness=1, contrast=1, sharpness=1 ) -> Image.Image: image = ImageEnhance.Sharpness( image=ImageEnhance.Brightness( image=ImageEnhance.Contrast( image=ImageEnhance.Color( image=( image if isinstance(image, Image.Image) is True else to_pil(image=image) ) ).enhance(color) ).enhance(contrast) ).enhance(brightness) ).enhance(sharpness) return image def ensure_odd( i: int, min_val: Union[None, int] = None, max_val: Union[None, int] = None, ) -> int: """Transforms an odd number into pair number by adding one Arguments: i {int} -- number Returns: int -- Odd number """ if (i > 0) and (i % 2 == 0): i += 1 if min_val is not None: return max(i, min_val) if max_val is not None: return min(i, max_val) return i def get_morphology_kernel(size: int, shape: int): """Builds morphology kernel :param size: kernel size, must be odd number :param shape: select shape of kernel :return: Morphology kernel """ size = ensure_odd(size) return cv2.getStructuringElement(shape, (size, size)) def close( image: Any, kernel_size: int = 3, kernel_shape: int = cv2.MORPH_ELLIPSE, rois: tuple = (), proc_times: int = 1, ): """Morphology - Close wrapper Arguments: image {numpy array} -- Source image kernel_size {int} -- kernel size kernel_shape {int} -- cv2 constant roi -- Region of Interest proc_times {int} -- iterations Returns: numpy array -- closed image """ morph_kernel = get_morphology_kernel(kernel_size, kernel_shape) if rois: result = image.copy() for roi in rois: r = roi.as_rect() result[r.top : r.bottom, r.left : r.right] = cv2.morphologyEx( result[r.top : r.bottom, r.left : r.right], cv2.MORPH_CLOSE, morph_kernel, iterations=proc_times, ) else: result = cv2.morphologyEx( image, cv2.MORPH_CLOSE, morph_kernel, iterations=proc_times ) return result def get_concat_h_multi_resize(im_list, resample=Image.Resampling.BICUBIC): min_height = min(im.height for im in im_list) im_list_resize = [ im.resize( (int(im.width * min_height / im.height), min_height), resample=resample ) for im in im_list ] total_width = sum(im.width for im in im_list_resize) dst = Image.new("RGB", (total_width, min_height)) pos_x = 0 for im in im_list_resize: dst.paste(im, (pos_x, 0)) pos_x += im.width return dst def get_concat_v_multi_resize(im_list, resample=Image.Resampling.BICUBIC): min_width = min(im.width for im in im_list) im_list_resize = [ im.resize((min_width, int(im.height * min_width / im.width)), resample=resample) for im in im_list ] total_height = sum(im.height for im in im_list_resize) dst = Image.new("RGB", (min_width, total_height)) pos_y = 0 for im in im_list_resize: dst.paste(im, (0, pos_y)) pos_y += im.height return dst def get_concat_tile_resize(im_list_2d, resample=Image.Resampling.BICUBIC): im_list_v = [ get_concat_h_multi_resize(im_list_h, resample=resample) for im_list_h in im_list_2d ] return get_concat_v_multi_resize(im_list_v, resample=resample) def get_tiles(img_list, row_count, resample=Image.Resampling.BICUBIC): if isinstance(img_list, np.ndarray) is False: img_list = np.asarray(img_list, dtype="object") return get_concat_tile_resize(np.split(img_list, row_count), resample)