misla122 commited on
Commit
769e1e0
·
verified ·
1 Parent(s): f768763

Upload 4 files

Browse files
Files changed (4) hide show
  1. README.md +6 -13
  2. app.py +116 -0
  3. requirements.txt +9 -0
  4. runtime.txt +1 -0
README.md CHANGED
@@ -1,14 +1,7 @@
1
- ---
2
- title: Md Ariful Islam
3
- emoji: 👁
4
- colorFrom: purple
5
- colorTo: green
6
- sdk: gradio
7
- sdk_version: 5.49.1
8
- app_file: app.py
9
- pinned: false
10
- license: apache-2.0
11
- short_description: 'Gaussian blur and lens blur effects based on user input. '
12
- ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
1
+ # Gaussian & Lens Blur Lab (Hugging Face Space)
 
 
 
 
 
 
 
 
 
 
 
2
 
3
+ This Space demonstrates two effects:
4
+ 1) **Gaussian Background Blur (subject sharp)** using SegFormer‑B0 for person segmentation.
5
+ 2) **Depth‑based Lens Blur** using DPT‑Hybrid MiDaS (blur radius ∝ depth).
6
+
7
+ Upload an image, choose an effect, adjust parameters, and click **Run**.
app.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+ # Ensure Hugging Face runs in PyTorch mode
4
+ os.environ["TRANSFORMERS_NO_TF"] = "1"
5
+
6
+ import numpy as np
7
+ from PIL import Image, ImageFilter
8
+ import gradio as gr
9
+
10
+ # Torch is imported lazily so the Space can boot even if torch takes time to install
11
+ import torch
12
+ from transformers import pipeline
13
+
14
+ # Device selection: GPU if available; otherwise CPU (-1)
15
+ DEVICE = 0 if torch.cuda.is_available() else -1
16
+
17
+ # Model identifiers
18
+ SEG_MODEL_NAME = "nvidia/segformer-b0-finetuned-ade-512-512"
19
+ DEPTH_MODEL_NAME = "Intel/dpt-hybrid-midas"
20
+ TARGET_SIZE = (512, 512)
21
+
22
+ # Pipelines: loaded once on process start
23
+ seg_pipe = pipeline("image-segmentation", model=SEG_MODEL_NAME, device=DEVICE, framework="pt")
24
+ depth_pipe = pipeline("depth-estimation", model=DEPTH_MODEL_NAME, device=DEVICE, framework="pt")
25
+
26
+ def resize_center_crop(img: Image.Image, size=(512, 512)) -> Image.Image:
27
+ """Resize with aspect ratio, center-crop to size."""
28
+ img = img.convert("RGB")
29
+ w, h = img.size
30
+ tw, th = size
31
+ scale = max(tw / w, th / h)
32
+ nw, nh = int(round(w * scale)), int(round(h * scale))
33
+ img = img.resize((nw, nh), Image.BICUBIC)
34
+ left, top = (nw - tw) // 2, (nh - th) // 2
35
+ return img.crop((left, top, left + tw, top + th))
36
+
37
+ def person_mask(img_512: Image.Image) -> Image.Image:
38
+ """Return a binary mask (L mode) with person=255, background=0; black if no person."""
39
+ results = seg_pipe(img_512)
40
+ person = None
41
+ for r in results:
42
+ if r.get("label", "").lower() == "person":
43
+ person = r; break
44
+ if person is None:
45
+ for r in results:
46
+ if "person" in r.get("label", "").lower():
47
+ person = r; break
48
+ if person is None:
49
+ return Image.new("L", img_512.size, 0)
50
+ m = person["mask"].convert("L")
51
+ m = (np.array(m) > 127).astype(np.uint8) * 255
52
+ return Image.fromarray(m, mode="L")
53
+
54
+ def gaussian_bg_blur(img_512: Image.Image, sigma: int = 15) -> Image.Image:
55
+ """Blur only the background (person stays sharp)."""
56
+ m = person_mask(img_512)
57
+ blurred = img_512.filter(ImageFilter.GaussianBlur(radius=int(sigma)))
58
+ return Image.composite(img_512, blurred, m)
59
+
60
+ def depth_lens_blur(img_512: Image.Image, max_radius: int = 15, keep_subject: bool = True) -> Image.Image:
61
+ """Apply per-pixel blur proportional to depth (farther = more blur)."""
62
+ out = depth_pipe(img_512)
63
+ d = out["depth"].resize(TARGET_SIZE, Image.BICUBIC)
64
+ dnp = np.array(d).astype(np.float32)
65
+ d01 = (dnp - dnp.min()) / (dnp.max() - dnp.min() + 1e-8) # 0..1 (brighter≈closer)
66
+ far = 1.0 - d01 # larger = farther
67
+ if keep_subject:
68
+ m = person_mask(img_512)
69
+ m01 = (np.array(m) > 127).astype(np.float32)
70
+ far = far * (1.0 - 0.85 * m01) # suppress blur on subject
71
+ # Build blurred pyramid and gather
72
+ max_radius = int(max(0, min(30, max_radius)))
73
+ radii = np.arange(max_radius + 1, dtype=np.int32)
74
+ idx = np.clip(np.rint(far * max_radius).astype(np.int32), 0, max_radius)
75
+ stack = []
76
+ for r in radii:
77
+ stack.append(img_512 if r == 0 else img_512.filter(ImageFilter.GaussianBlur(radius=int(r))))
78
+ stack_np = np.stack([np.array(im) for im in stack], axis=0) # [R+1,H,W,3]
79
+ H, W = idx.shape
80
+ h = np.arange(H)[:, None]
81
+ w = np.arange(W)[None, :]
82
+ out_np = stack_np[idx, h, w]
83
+ return Image.fromarray(out_np.astype(np.uint8))
84
+
85
+ def run(image: Image.Image, effect: str, sigma: int, max_radius: int, keep_subject: bool):
86
+ if image is None:
87
+ return None, None
88
+ img_512 = resize_center_crop(image, TARGET_SIZE)
89
+ if effect == "Gaussian Background Blur (subject sharp)":
90
+ out = gaussian_bg_blur(img_512, sigma=int(sigma))
91
+ else:
92
+ out = depth_lens_blur(img_512, max_radius=int(max_radius), keep_subject=keep_subject)
93
+ return img_512, out
94
+
95
+ with gr.Blocks(title="Gaussian & Lens Blur Lab") as demo:
96
+ gr.Markdown("# Gaussian & Lens Blur Lab\nUpload an image and compare effects.")
97
+ with gr.Row():
98
+ with gr.Column():
99
+ in_img = gr.Image(type="pil", label="Upload image")
100
+ effect = gr.Radio(
101
+ ["Gaussian Background Blur (subject sharp)", "Depth-based Lens Blur"],
102
+ value="Gaussian Background Blur (subject sharp)",
103
+ label="Effect"
104
+ )
105
+ sigma = gr.Slider(1, 40, value=15, step=1, label="Gaussian sigma")
106
+ max_r = gr.Slider(4, 30, value=15, step=1, label="Max blur radius (lens blur)")
107
+ keep = gr.Checkbox(True, label="Keep detected subject sharper (lens blur)")
108
+ btn = gr.Button("Run")
109
+ with gr.Column():
110
+ out_a = gr.Image(label="Preprocessed 512×512")
111
+ out_b = gr.Image(label="Result")
112
+ btn.click(run, inputs=[in_img, effect, sigma, max_r, keep], outputs=[out_a, out_b])
113
+
114
+ if __name__ == "__main__":
115
+ # On Spaces, just `python app.py` is sufficient
116
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ gradio==4.44.0
2
+ transformers==4.44.2
3
+ accelerate==0.34.2
4
+ timm==0.9.12
5
+ pillow==10.4.0
6
+ safetensors>=0.4.3
7
+ numpy>=1.26
8
+ torch==2.3.1
9
+ torchvision==0.18.1
runtime.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ python-3.10