Spaces:
Running
Running
import sys | |
import functools | |
import numpy as np | |
import cv2 | |
import cmapy | |
from PIL import Image | |
import matplotlib | |
# BUGFIX in cmapy.py | |
def cmap(cmap_name, rgb_order=False): | |
""" | |
Extract colormap color information as a LUT compatible with cv2.applyColormap(). | |
Default channel order is BGR. | |
Args: | |
cmap_name: string, name of the colormap. | |
rgb_order: boolean, if false or not set, the returned array will be in | |
BGR order (standard OpenCV format). If true, the order | |
will be RGB. | |
Returns: | |
A numpy array of type uint8 containing the colormap. | |
""" | |
c_map = matplotlib.colormaps.get_cmap(cmap_name) | |
rgba_data = matplotlib.cm.ScalarMappable(cmap=c_map).to_rgba( | |
np.arange(0, 1.0, 1.0 / 256.0), bytes=True | |
) | |
rgba_data = rgba_data[:, 0:-1].reshape((256, 1, 3)) | |
# Convert to BGR (or RGB), uint8, for OpenCV. | |
cmap = np.zeros((256, 1, 3), np.uint8) | |
if not rgb_order: | |
cmap[:, :, :] = rgba_data[:, :, ::-1] | |
else: | |
cmap[:, :, :] = rgba_data[:, :, :] | |
return cmap | |
# If python 3, redefine cmap() to use lru_cache. | |
if sys.version_info > (3, 0): | |
cmap = functools.lru_cache(maxsize=200)(cmap) | |
def alpha_composite(img, msk, opacity=0.5, colormap=None, alpha_image=None, alpha_mask=None, red_mask=False): | |
"""Alpha composite an RGBA image (img) and a grayscale mask (msk). | |
- If alpha_image is None, img's alpha channel is used (or, if not present, | |
initialized to all 255). | |
- If alpha_mask is None, msk is overlaid on img only where img's alpha | |
channel is not 0. | |
- If alpha_mask is not None, the above behavior is overridden and msk is | |
overlaid on img only where alpha_mask is not 0.""" | |
# only HWC numpy arrays allowed | |
assert isinstance(img, np.ndarray), f'Input image must be a numpy array. Got {type(img)}' | |
assert isinstance(msk, np.ndarray), f'Input mask must be a numpy array. Got {type(msk)}' | |
if alpha_mask is not None: | |
assert isinstance(alpha_mask, np.ndarray), f'Alpha mask must be a numpy array. Got {type(alpha_mask)}' | |
assert alpha_mask.dtype in [np.float32, bool], f'Alpha mask must be of type np.float32 or bool. Got {alpha_mask.dtype}' | |
assert alpha_mask.shape[2] == 1, f'Alpha mask must be formatted as HWC, with C = 1. Got a shape of {msk.shape}' | |
assert img.shape[2] in [3,4], f'Input image must be formatted as HWC, with C = 3,4. Got a shape of {img.shape}' | |
assert msk.shape[2] == 1, f'Input mask must be formatted as HWC, with C = 1. Got a shape of {msk.shape}' | |
assert (opacity >= 0) and (opacity <= 1), f'Mask opacity must be between 0 and 1. Got {opacity}' | |
# to avoid modifying the original arrays | |
img = img.copy() | |
msk = msk.copy() | |
if img.shape[2] == 3: | |
# add alpha channel to img | |
img = np.concatenate([ | |
img, | |
np.full((img.shape[0], img.shape[1], 1), 255, dtype=np.uint8) | |
], axis=-1) | |
if alpha_image is None: | |
# initialize alpha_image to all Trues | |
alpha_image = img[:,:,[3]] | |
# convert alpha image to bool | |
alpha_image = alpha_image.astype(bool) | |
if alpha_mask is None: | |
# initialize alpha_mask to alpha_image | |
alpha_mask = alpha_image # so that alpha_mask is AT LEAST as restrictive as alpha_image | |
# convert alpha mask to bool | |
alpha_mask = alpha_mask.astype(bool) | |
if msk.dtype != np.uint8: | |
# convert mask to a uint8 grayscale image ([0,1] -> [0,255]) | |
# NB: normalize the pixels of the mask we are interested in to [0,1] | |
# before passing it as input!!! | |
msk = (msk * 255).astype(np.uint8) | |
# convert mask from grayscale to RGBA | |
msk = cv2.cvtColor(msk, cv2.COLOR_GRAY2RGBA) | |
if colormap is not None: | |
# apply specified colormap to msk | |
# NB: values near 0 will be converted to the first colors of the chosen | |
# colormap, whereas values near 255 will be converted to the last colors | |
msk[:,:,:3] = cmapy.colorize(msk[:,:,:3], colormap, rgb_order=True) | |
elif red_mask: | |
# convert white to red | |
msk[:,:,[1,2]] = 0 | |
# apply alpha_image to img's alpha channel | |
img[:,:,[3]] = (alpha_image * img[:,:,[3]]).astype(np.uint8) | |
# apply alpha_mask and opacity to msk's alpha channel | |
msk[:,:,[3]] = (alpha_mask * opacity * msk[:,:,[3]]).astype(np.uint8) | |
# alpha compositing | |
img_pil = Image.fromarray(img) | |
msk_pil = Image.fromarray(msk) | |
img_pil.alpha_composite(msk_pil) | |
return np.array(img_pil) | |