File size: 2,165 Bytes
5dbde27
 
 
 
e7b5496
 
 
5dbde27
e7b5496
 
 
5dbde27
188e92b
e7b5496
 
5dbde27
188e92b
e7b5496
5dbde27
188e92b
e7b5496
 
188e92b
5dbde27
188e92b
 
 
e7b5496
188e92b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e7b5496
 
5dbde27
e7b5496
 
 
188e92b
e7b5496
 
 
188e92b
e7b5496
188e92b
 
e7b5496
5dbde27
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import gradio as gr
from PIL import Image
import numpy as np

def brightness_to_opacity_overlay(foreground_img, background_img, invert_opacity=False):
    if foreground_img is None or background_img is None:
        return None

    # Resize foreground to match background
    bg = background_img.convert("RGBA")
    fg = foreground_img.convert("RGB").resize(bg.size)

    # Convert to luminance (grayscale)
    fg_array = np.array(fg)
    luminance = np.dot(fg_array[...,:3], [0.299, 0.587, 0.114]).astype(np.uint8)

    # Invert if requested
    alpha = 255 - luminance if invert_opacity else luminance

    # Create white RGBA image with computed alpha
    white_rgb = np.ones_like(fg_array) * 255
    rgba_array = np.dstack((white_rgb, alpha)).astype(np.uint8)
    overlay = Image.fromarray(rgba_array, mode="RGBA")

    # Manual alpha blending
    bg_arr = np.array(bg).astype(np.float32) / 255.0
    ov_arr = np.array(overlay).astype(np.float32) / 255.0

    # Extract alpha channels
    alpha_bg = bg_arr[..., 3:4]
    alpha_ov = ov_arr[..., 3:4]

    # Composite alpha and color
    out_alpha = alpha_ov + alpha_bg * (1 - alpha_ov)
    out_rgb = (
        ov_arr[..., :3] * alpha_ov +
        bg_arr[..., :3] * alpha_bg * (1 - alpha_ov)
    ) / np.clip(out_alpha, 1e-6, 1)

    # Combine and convert to final image
    out_image = np.dstack((out_rgb, out_alpha)).clip(0, 1) * 255
    out_image = Image.fromarray(out_image.astype(np.uint8), mode="RGBA")

    return out_image

# Gradio UI
iface = gr.Interface(
    fn=brightness_to_opacity_overlay,
    inputs=[
        gr.Image(type="pil", label="Mask Source (Brightness to Alpha)"),
        gr.Image(type="pil", label="Background Image (with or without transparency)"),
        gr.Checkbox(label="Invert Opacity", value=False)
    ],
    outputs=gr.Image(type="pil", label="Final Composite"),
    title="Brightness-to-Alpha Overlay Tool (with Transparency Fix)",
    description=(
        "Uses the brightness of the first image as alpha, resizes to match the second image, "
        "and overlays correctly even when the background has transparency."
    )
)

if __name__ == "__main__":
    iface.launch()