""" Source url: https://github.com/OPHoperHPO/image-background-remove-tool Author: Nikita Selin (OPHoperHPO)[https://github.com/OPHoperHPO]. License: Apache License 2.0 """ import PIL.Image import torch from carvekit.utils.image_utils import to_tensor def composite( foreground: PIL.Image.Image, background: PIL.Image.Image, alpha: PIL.Image.Image, device="cpu", ): """ Composites foreground with background by following https://pymatting.github.io/intro.html#alpha-matting math formula. Args: device: Processing device foreground: Image that will be pasted to background image with following alpha mask. background: Background image alpha: Alpha Image Returns: Composited image as PIL.Image instance. """ foreground = foreground.convert("RGBA") background = background.convert("RGBA") alpha_rgba = alpha.convert("RGBA") alpha_l = alpha.convert("L") fg = to_tensor(foreground).to(device) alpha_rgba = to_tensor(alpha_rgba).to(device) alpha_l = to_tensor(alpha_l).to(device) bg = to_tensor(background).to(device) alpha_l = alpha_l / 255 alpha_rgba = alpha_rgba / 255 bg = torch.where(torch.logical_not(alpha_rgba >= 1), bg, fg) bg[:, :, 0] = alpha_l[:, :] * fg[:, :, 0] + (1 - alpha_l[:, :]) * bg[:, :, 0] bg[:, :, 1] = alpha_l[:, :] * fg[:, :, 1] + (1 - alpha_l[:, :]) * bg[:, :, 1] bg[:, :, 2] = alpha_l[:, :] * fg[:, :, 2] + (1 - alpha_l[:, :]) * bg[:, :, 2] bg[:, :, 3] = alpha_l[:, :] * 255 del alpha_l, alpha_rgba, fg return PIL.Image.fromarray(bg.cpu().numpy()).convert("RGBA") def apply_mask( image: PIL.Image.Image, mask: PIL.Image.Image, device="cpu" ) -> PIL.Image.Image: """ Applies mask to foreground. Args: device: Processing device. image: Image with background. mask: Alpha Channel mask for this image. Returns: Image without background, where mask was black. """ background = PIL.Image.new("RGBA", image.size, color=(130, 130, 130, 0)) return composite(image, background, mask, device=device).convert("RGBA") def extract_alpha_channel(image: PIL.Image.Image) -> PIL.Image.Image: """ Extracts alpha channel from the RGBA image. Args: image: RGBA PIL image Returns: RGBA alpha channel image """ alpha = image.split()[-1] bg = PIL.Image.new("RGBA", image.size, (0, 0, 0, 255)) bg.paste(alpha, mask=alpha) return bg.convert("RGBA")