Update app.py
Browse files
app.py
CHANGED
@@ -6,56 +6,55 @@ def brightness_to_opacity_overlay(foreground_img, background_img, invert_opacity
|
|
6 |
if foreground_img is None or background_img is None:
|
7 |
return None
|
8 |
|
9 |
-
#
|
10 |
bg = background_img.convert("RGBA")
|
11 |
fg = foreground_img.convert("RGB").resize(bg.size)
|
12 |
|
13 |
-
# Convert to luminance (
|
14 |
-
|
15 |
-
|
16 |
|
17 |
-
#
|
18 |
-
alpha = 255 -
|
19 |
|
20 |
-
# Create white RGBA
|
21 |
-
white_rgb = np.
|
22 |
-
|
23 |
-
overlay = Image.fromarray(
|
24 |
|
25 |
-
#
|
26 |
-
|
27 |
-
|
28 |
|
29 |
-
|
30 |
-
alpha_bg =
|
31 |
-
alpha_ov = ov_arr[..., 3:4]
|
32 |
|
33 |
-
#
|
34 |
-
|
35 |
-
|
36 |
-
ov_arr[..., :3] * alpha_ov +
|
37 |
-
bg_arr[..., :3] * alpha_bg * (1 - alpha_ov)
|
38 |
-
) / np.clip(out_alpha, 1e-6, 1)
|
39 |
|
40 |
-
#
|
41 |
-
|
42 |
-
out_image = Image.fromarray(out_image.astype(np.uint8), mode="RGBA")
|
43 |
|
44 |
-
|
|
|
|
|
|
|
|
|
45 |
|
46 |
# Gradio UI
|
47 |
iface = gr.Interface(
|
48 |
fn=brightness_to_opacity_overlay,
|
49 |
inputs=[
|
50 |
gr.Image(type="pil", label="Mask Source (Brightness to Alpha)"),
|
51 |
-
gr.Image(type="pil", label="Background Image (with
|
52 |
gr.Checkbox(label="Invert Opacity", value=False)
|
53 |
],
|
54 |
-
outputs=gr.Image(type="pil", label="
|
55 |
-
title="Brightness-to-Alpha Overlay
|
56 |
description=(
|
57 |
-
"Uses the brightness of
|
58 |
-
"
|
59 |
)
|
60 |
)
|
61 |
|
|
|
6 |
if foreground_img is None or background_img is None:
|
7 |
return None
|
8 |
|
9 |
+
# Ensure images are RGBA and same size
|
10 |
bg = background_img.convert("RGBA")
|
11 |
fg = foreground_img.convert("RGB").resize(bg.size)
|
12 |
|
13 |
+
# Convert to luminance (brightness)
|
14 |
+
fg_np = np.array(fg)
|
15 |
+
brightness = np.dot(fg_np[..., :3], [0.299, 0.587, 0.114]).astype(np.uint8)
|
16 |
|
17 |
+
# Optionally invert
|
18 |
+
alpha = 255 - brightness if invert_opacity else brightness
|
19 |
|
20 |
+
# Create white RGBA with computed alpha
|
21 |
+
white_rgb = np.full_like(fg_np, 255)
|
22 |
+
overlay_rgba = np.dstack((white_rgb, alpha)).astype(np.uint8)
|
23 |
+
overlay = Image.fromarray(overlay_rgba, mode="RGBA")
|
24 |
|
25 |
+
# Use the alpha from overlay as a mask on the background
|
26 |
+
bg_np = np.array(bg).astype(np.float32)
|
27 |
+
ov_np = np.array(overlay).astype(np.float32)
|
28 |
|
29 |
+
alpha_fg = ov_np[..., 3:4] / 255.0
|
30 |
+
alpha_bg = bg_np[..., 3:4] / 255.0
|
|
|
31 |
|
32 |
+
# Blend RGB
|
33 |
+
out_rgb = (ov_np[..., :3] * alpha_fg + bg_np[..., :3] * alpha_bg * (1 - alpha_fg))
|
34 |
+
out_alpha = alpha_fg + alpha_bg * (1 - alpha_fg)
|
|
|
|
|
|
|
35 |
|
36 |
+
# Avoid divide-by-zero
|
37 |
+
out_rgb = np.divide(out_rgb, out_alpha, where=(out_alpha != 0))
|
|
|
38 |
|
39 |
+
# Combine back to RGBA
|
40 |
+
out_rgba = np.dstack((out_rgb, out_alpha)) * 255
|
41 |
+
result = Image.fromarray(out_rgba.astype(np.uint8), mode="RGBA")
|
42 |
+
|
43 |
+
return result
|
44 |
|
45 |
# Gradio UI
|
46 |
iface = gr.Interface(
|
47 |
fn=brightness_to_opacity_overlay,
|
48 |
inputs=[
|
49 |
gr.Image(type="pil", label="Mask Source (Brightness to Alpha)"),
|
50 |
+
gr.Image(type="pil", label="Background Image (with transparency OK)"),
|
51 |
gr.Checkbox(label="Invert Opacity", value=False)
|
52 |
],
|
53 |
+
outputs=gr.Image(type="pil", label="Composite Result"),
|
54 |
+
title="Brightness-to-Alpha Overlay (Transparent-Safe)",
|
55 |
description=(
|
56 |
+
"Uses the brightness of one image as an alpha mask and overlays it "
|
57 |
+
"on a background image — works properly even when background has transparency."
|
58 |
)
|
59 |
)
|
60 |
|