Flux-TRELLIS / blend_processor.py
gokaygokay's picture
blend
66757e7
raw
history blame
10.4 kB
import gradio as gr
import numpy as np
import cv2
from PIL import Image, ImageChops
from skimage import img_as_float, img_as_ubyte
import copy
from typing import Optional, Union
def cv22ski(cv2_image: np.ndarray) -> np.ndarray:
"""Convert CV2 image to skimage float format"""
return img_as_float(cv2_image)
def ski2cv2(ski: np.ndarray) -> np.ndarray:
"""Convert skimage float format to CV2 image"""
return img_as_ubyte(ski)
def cv22pil(cv2_img: np.ndarray) -> Image.Image:
"""Convert CV2 image to PIL Image"""
cv2_img = cv2.cvtColor(cv2_img, cv2.COLOR_BGR2RGB)
return Image.fromarray(cv2_img)
def pil2cv2(pil_img: Image.Image) -> np.ndarray:
"""Convert PIL Image to CV2 image"""
np_img_array = np.asarray(pil_img)
return cv2.cvtColor(np_img_array, cv2.COLOR_RGB2BGR)
def blend_color_burn(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply color burn blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
img = 1 - (1 - img_2) / (img_1 + 0.001)
mask_1 = img < 0
mask_2 = img > 1
img = img * (1 - mask_1)
img = img * (1 - mask_2) + mask_2
return cv22pil(ski2cv2(img))
def blend_color_dodge(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply color dodge blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
img = img_2 / (1.0 - img_1 + 0.001)
mask_2 = img > 1
img = img * (1 - mask_2) + mask_2
return cv22pil(ski2cv2(img))
def blend_linear_burn(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply linear burn blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
img = img_1 + img_2 - 1
mask_1 = img < 0
img = img * (1 - mask_1)
return cv22pil(ski2cv2(img))
def blend_linear_dodge(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply linear dodge blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
img = img_1 + img_2
mask_2 = img > 1
img = img * (1 - mask_2) + mask_2
return cv22pil(ski2cv2(img))
def blend_lighten(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply lighten blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
img = img_1 - img_2
mask = img > 0
img = img_1 * mask + img_2 * (1 - mask)
return cv22pil(ski2cv2(img))
def blend_dark(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply darken blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
img = img_1 - img_2
mask = img < 0
img = img_1 * mask + img_2 * (1 - mask)
return cv22pil(ski2cv2(img))
def blend_screen(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply screen blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
img = 1 - (1 - img_1) * (1 - img_2)
return cv22pil(ski2cv2(img))
def blend_overlay(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply overlay blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
mask = img_2 < 0.5
img = 2 * img_1 * img_2 * mask + (1 - mask) * (1 - 2 * (1 - img_1) * (1 - img_2))
return cv22pil(ski2cv2(img))
def blend_soft_light(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply soft light blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
mask = img_1 < 0.5
T1 = (2 * img_1 - 1) * (img_2 - img_2 * img_2) + img_2
T2 = (2 * img_1 - 1) * (np.sqrt(img_2) - img_2) + img_2
img = T1 * mask + T2 * (1 - mask)
return cv22pil(ski2cv2(img))
def blend_hard_light(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply hard light blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
mask = img_1 < 0.5
T1 = 2 * img_1 * img_2
T2 = 1 - 2 * (1 - img_1) * (1 - img_2)
img = T1 * mask + T2 * (1 - mask)
return cv22pil(ski2cv2(img))
def blend_vivid_light(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply vivid light blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
mask = img_1 < 0.5
T1 = 1 - (1 - img_2) / (2 * img_1 + 0.001)
T2 = img_2 / (2 * (1 - img_1) + 0.001)
mask_1 = T1 < 0
mask_2 = T2 > 1
T1 = T1 * (1 - mask_1)
T2 = T2 * (1 - mask_2) + mask_2
img = T1 * mask + T2 * (1 - mask)
return cv22pil(ski2cv2(img))
def blend_pin_light(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply pin light blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
mask_1 = img_2 < (img_1 * 2 - 1)
mask_2 = img_2 > 2 * img_1
T1 = 2 * img_1 - 1
T2 = img_2
T3 = 2 * img_1
img = T1 * mask_1 + T2 * (1 - mask_1) * (1 - mask_2) + T3 * mask_2
return cv22pil(ski2cv2(img))
def blend_linear_light(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply linear light blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
img = img_2 + img_1 * 2 - 1
mask_1 = img < 0
mask_2 = img > 1
img = img * (1 - mask_1)
img = img * (1 - mask_2) + mask_2
return cv22pil(ski2cv2(img))
def blend_hard_mix(background_image: Image.Image, layer_image: Image.Image) -> Image.Image:
"""Apply hard mix blend mode"""
img_1 = cv22ski(pil2cv2(background_image))
img_2 = cv22ski(pil2cv2(layer_image))
img = img_1 + img_2
mask = img_1 + img_2 > 1
img = img * (1 - mask) + mask
img = img * mask
return cv22pil(ski2cv2(img))
def chop_image(background_image: Image.Image, layer_image: Image.Image, blend_mode: str, opacity: int) -> Image.Image:
"""Apply blend mode and opacity to images"""
ret_image = background_image
blend_functions = {
'normal': lambda: copy.deepcopy(layer_image),
'multiply': lambda: ImageChops.multiply(background_image, layer_image),
'screen': lambda: ImageChops.screen(background_image, layer_image),
'add': lambda: ImageChops.add(background_image, layer_image, 1, 0),
'subtract': lambda: ImageChops.subtract(background_image, layer_image, 1, 0),
'difference': lambda: ImageChops.difference(background_image, layer_image),
'darker': lambda: ImageChops.darker(background_image, layer_image),
'lighter': lambda: ImageChops.lighter(background_image, layer_image),
'color_burn': lambda: blend_color_burn(background_image, layer_image),
'color_dodge': lambda: blend_color_dodge(background_image, layer_image),
'linear_burn': lambda: blend_linear_burn(background_image, layer_image),
'linear_dodge': lambda: blend_linear_dodge(background_image, layer_image),
'overlay': lambda: blend_overlay(background_image, layer_image),
'soft_light': lambda: blend_soft_light(background_image, layer_image),
'hard_light': lambda: blend_hard_light(background_image, layer_image),
'vivid_light': lambda: blend_vivid_light(background_image, layer_image),
'pin_light': lambda: blend_pin_light(background_image, layer_image),
'linear_light': lambda: blend_linear_light(background_image, layer_image),
'hard_mix': lambda: blend_hard_mix(background_image, layer_image)
}
if blend_mode in blend_functions:
ret_image = blend_functions[blend_mode]()
# Apply opacity
if opacity == 0:
ret_image = background_image
elif opacity < 100:
alpha = 1.0 - float(opacity) / 100
ret_image = Image.blend(ret_image, background_image, alpha)
return ret_image
def process_images(background: Optional[np.ndarray],
layer: Optional[np.ndarray],
blend_mode: str,
opacity: float) -> Optional[np.ndarray]:
"""Process images with selected blend mode and opacity"""
if background is None or layer is None:
return None
# Convert numpy arrays to PIL Images
background_pil = Image.fromarray(background)
layer_pil = Image.fromarray(layer)
# Ensure images are in RGB mode
background_pil = background_pil.convert('RGB')
layer_pil = layer_pil.convert('RGB')
# Apply blend mode
result = chop_image(background_pil, layer_pil, blend_mode, int(opacity * 100))
# Convert back to numpy array
return np.array(result)
def create_blend_tab():
"""Create the blend modes tab interface"""
with gr.Tab("Blend Modes"):
with gr.Row():
with gr.Column():
background_image = gr.Image(label="Background Image", height=256)
layer_image = gr.Image(label="Layer Image", height=256)
blend_mode = gr.Dropdown(
choices=[
"normal", "multiply", "screen", "overlay",
"soft_light", "hard_light", "color_burn", "color_dodge",
"linear_burn", "linear_dodge", "vivid_light", "linear_light",
"pin_light", "hard_mix", "difference", "add", "subtract",
"darker", "lighter"
],
value="normal",
label="Blend Mode"
)
opacity = gr.Slider(
minimum=0.0,
maximum=1.0,
value=1.0,
step=0.01,
label="Opacity"
)
blend_btn = gr.Button("Apply Blend")
with gr.Column():
output_image = gr.Image(label="Blended Image")
blend_btn.click(
fn=process_images,
inputs=[background_image, layer_image, blend_mode, opacity],
outputs=output_image
)