""" Source url: https://github.com/OPHoperHPO/image-background-remove-tool Author: Nikita Selin (OPHoperHPO)[https://github.com/OPHoperHPO]. License: Apache License 2.0 """ import pathlib from typing import Union, Any, Tuple import PIL.Image import numpy as np import torch ALLOWED_SUFFIXES = [".jpg", ".jpeg", ".bmp", ".png", ".webp"] def to_tensor(x: Any) -> torch.Tensor: """ Returns a PIL.Image.Image as torch tensor without swap tensor dims. Args: x: PIL.Image.Image instance Returns: torch.Tensor instance """ return torch.tensor(np.array(x, copy=True)) def load_image(file: Union[str, pathlib.Path, PIL.Image.Image]) -> PIL.Image.Image: """Returns a PIL.Image.Image class by string path or pathlib path or PIL.Image.Image instance Args: file: File path or PIL.Image.Image instance Returns: PIL.Image.Image instance Raises: ValueError: If file not exists or file is directory or file isn't an image or file is not correct PIL Image """ if isinstance(file, str) and is_image_valid(pathlib.Path(file)): return PIL.Image.open(file) elif isinstance(file, PIL.Image.Image): return file elif isinstance(file, pathlib.Path) and is_image_valid(file): return PIL.Image.open(str(file)) else: raise ValueError("Unknown input file type") def convert_image(image: PIL.Image.Image, mode="RGB") -> PIL.Image.Image: """Performs image conversion to correct color mode Args: image: PIL.Image.Image instance mode: Colort Mode to convert Returns: PIL.Image.Image instance Raises: ValueError: If image hasn't convertable color mode, or it is too small """ if is_image_valid(image): return image.convert(mode) def is_image_valid(image: Union[pathlib.Path, PIL.Image.Image]) -> bool: """This function performs image validation. Args: image: Path to the image or PIL.Image.Image instance being checked. Returns: True if image is valid Raises: ValueError: If file not a valid image path or image hasn't convertable color mode, or it is too small """ if isinstance(image, pathlib.Path): if not image.exists(): raise ValueError("File is not exists") elif image.is_dir(): raise ValueError("File is a directory") elif image.suffix.lower() not in ALLOWED_SUFFIXES: raise ValueError( f"Unsupported image format. Supported file formats: {', '.join(ALLOWED_SUFFIXES)}" ) elif isinstance(image, PIL.Image.Image): if not (image.size[0] > 32 and image.size[1] > 32): raise ValueError("Image should be bigger then (32x32) pixels.") elif image.mode not in ["RGB", "RGBA", "L"]: raise ValueError("Wrong image color mode.") else: raise ValueError("Unknown input file type") return True def transparency_paste( bg_img: PIL.Image.Image, fg_img: PIL.Image.Image, box=(0, 0) ) -> PIL.Image.Image: """ Inserts an image into another image while maintaining transparency. Args: bg_img: background image fg_img: foreground image box: place to paste Returns: Background image with pasted foreground image at point or in the specified box """ fg_img_trans = PIL.Image.new("RGBA", bg_img.size) fg_img_trans.paste(fg_img, box, mask=fg_img) new_img = PIL.Image.alpha_composite(bg_img, fg_img_trans) return new_img def add_margin( pil_img: PIL.Image.Image, top: int, right: int, bottom: int, left: int, color: Tuple[int, int, int, int], ) -> PIL.Image.Image: """ Adds margin to the image. Args: pil_img: Image that needed to add margin. top: pixels count at top side right: pixels count at right side bottom: pixels count at bottom side left: pixels count at left side color: color of margin Returns: Image with margin. """ width, height = pil_img.size new_width = width + right + left new_height = height + top + bottom # noinspection PyTypeChecker result = PIL.Image.new(pil_img.mode, (new_width, new_height), color) result.paste(pil_img, (left, top)) return result