Update app.py
Browse files
app.py
CHANGED
@@ -10,39 +10,54 @@ def brightness_to_opacity_overlay(foreground_img, background_img, invert_opacity
|
|
10 |
bg = background_img.convert("RGBA")
|
11 |
fg = foreground_img.convert("RGB").resize(bg.size)
|
12 |
|
13 |
-
# Convert
|
14 |
fg_array = np.array(fg)
|
15 |
luminance = np.dot(fg_array[...,:3], [0.299, 0.587, 0.114]).astype(np.uint8)
|
16 |
|
17 |
-
#
|
18 |
alpha = 255 - luminance if invert_opacity else luminance
|
19 |
|
20 |
-
#
|
21 |
white_rgb = np.ones_like(fg_array) * 255
|
22 |
rgba_array = np.dstack((white_rgb, alpha)).astype(np.uint8)
|
23 |
-
|
24 |
|
25 |
-
#
|
26 |
-
|
|
|
27 |
|
28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
|
30 |
# Gradio UI
|
31 |
iface = gr.Interface(
|
32 |
fn=brightness_to_opacity_overlay,
|
33 |
inputs=[
|
34 |
gr.Image(type="pil", label="Mask Source (Brightness to Alpha)"),
|
35 |
-
gr.Image(type="pil", label="Background Image"),
|
36 |
gr.Checkbox(label="Invert Opacity", value=False)
|
37 |
],
|
38 |
outputs=gr.Image(type="pil", label="Final Composite"),
|
39 |
-
title="Brightness-to-Alpha Overlay Tool",
|
40 |
description=(
|
41 |
-
"
|
42 |
-
"
|
43 |
)
|
44 |
)
|
45 |
|
46 |
-
# Run the app
|
47 |
if __name__ == "__main__":
|
48 |
iface.launch()
|
|
|
10 |
bg = background_img.convert("RGBA")
|
11 |
fg = foreground_img.convert("RGB").resize(bg.size)
|
12 |
|
13 |
+
# Convert to luminance (grayscale)
|
14 |
fg_array = np.array(fg)
|
15 |
luminance = np.dot(fg_array[...,:3], [0.299, 0.587, 0.114]).astype(np.uint8)
|
16 |
|
17 |
+
# Invert if requested
|
18 |
alpha = 255 - luminance if invert_opacity else luminance
|
19 |
|
20 |
+
# Create white RGBA image with computed alpha
|
21 |
white_rgb = np.ones_like(fg_array) * 255
|
22 |
rgba_array = np.dstack((white_rgb, alpha)).astype(np.uint8)
|
23 |
+
overlay = Image.fromarray(rgba_array, mode="RGBA")
|
24 |
|
25 |
+
# Manual alpha blending
|
26 |
+
bg_arr = np.array(bg).astype(np.float32) / 255.0
|
27 |
+
ov_arr = np.array(overlay).astype(np.float32) / 255.0
|
28 |
|
29 |
+
# Extract alpha channels
|
30 |
+
alpha_bg = bg_arr[..., 3:4]
|
31 |
+
alpha_ov = ov_arr[..., 3:4]
|
32 |
+
|
33 |
+
# Composite alpha and color
|
34 |
+
out_alpha = alpha_ov + alpha_bg * (1 - alpha_ov)
|
35 |
+
out_rgb = (
|
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 |
+
# Combine and convert to final image
|
41 |
+
out_image = np.dstack((out_rgb, out_alpha)).clip(0, 1) * 255
|
42 |
+
out_image = Image.fromarray(out_image.astype(np.uint8), mode="RGBA")
|
43 |
+
|
44 |
+
return out_image
|
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 or without transparency)"),
|
52 |
gr.Checkbox(label="Invert Opacity", value=False)
|
53 |
],
|
54 |
outputs=gr.Image(type="pil", label="Final Composite"),
|
55 |
+
title="Brightness-to-Alpha Overlay Tool (with Transparency Fix)",
|
56 |
description=(
|
57 |
+
"Uses the brightness of the first image as alpha, resizes to match the second image, "
|
58 |
+
"and overlays correctly even when the background has transparency."
|
59 |
)
|
60 |
)
|
61 |
|
|
|
62 |
if __name__ == "__main__":
|
63 |
iface.launch()
|