salman555 commited on
Commit
3f32aed
Β·
verified Β·
1 Parent(s): cb762a0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +175 -52
app.py CHANGED
@@ -1,68 +1,191 @@
1
  import os
2
- import tempfile
3
- import gradio as gr
4
- from rembg import remove
 
5
  from PIL import Image
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
- # Force ONNXRuntime to CPU only
8
- os.environ["ORT_PROVIDERS"] = "CPUExecutionProvider"
 
 
 
 
 
9
 
10
- def remove_background(input_image: Image.Image) -> Image.Image:
11
- """Your existing remover."""
12
- return remove(input_image)
 
 
 
 
 
 
 
 
 
13
 
14
- def remove_and_save(img: Image.Image):
 
 
15
  """
16
- 1) remove background,
17
- 2) save to a temp PNG,
18
- 3) return (PIL.Image for preview, file path for DownloadButton).
 
 
 
19
  """
20
- result = remove_background(img)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
22
- result.save(tmp.name, format="PNG")
23
  tmp.close()
24
- return result, tmp.name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
- with gr.Blocks() as demo:
27
- gr.Markdown("## πŸ–ΌοΈ Background Remover")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  gr.Markdown(
29
- "Upload an image and click **Remove Background** to get a transparent PNG. \n"
30
- "**Note:** CPU-only ONNX Runtime (no GPU needed)."
 
 
 
31
  )
32
 
 
33
  with gr.Row():
34
- original = gr.Image(type="pil", label="Original")
35
- result = gr.Image(type="pil", label="Result")
36
-
37
- # Stack Remove + Download vertically
38
- with gr.Column(elem_id="controls"):
39
- remove_btn = gr.Button("βœ‚οΈ Remove Background", variant="primary")
40
- download_btn = gr.DownloadButton("⬇️ Download PNG")
41
-
42
- remove_btn.click(
43
- fn=remove_and_save,
44
- inputs=original,
45
- outputs=[result, download_btn],
46
- )
47
 
48
- # Centered footer
49
- demo.css = """
50
- #controls { align-items: start; gap: 0.5rem; }
51
- .footer { text-align: center; margin-top: 2rem; color: #666; font-size:0.9rem; }
52
- .social-icons a { margin: 0 0.5rem; text-decoration: none; color: inherit; }
53
- """
 
 
 
 
 
 
54
 
55
- gr.HTML("""
56
- <div class="footer">
57
- Made by Salman Alfarisi β€’ 2025<br>
58
- <span class="social-icons">
59
- <a href="https://github.com/salmanalfarisi11" target="_blank">GitHub</a> |
60
- <a href="https://www.instagram.com/faris.salman111/" target="_blank">Instagram</a> |
61
- <a href="https://id.linkedin.com/in/salmanalfarisi11" target="_blank">LinkedIn</a>
62
- </span><br>
63
- Source code on <a href="https://github.com/salmanalfarisi11" target="_blank">GitHub</a>
64
- </div>
65
- """)
66
-
67
- if __name__ == "__main__":
68
- demo.launch()
 
1
  import os
2
+ import math
3
+ import uuid
4
+ import numpy as np
5
+ import onnxruntime as ort
6
  from PIL import Image
7
+ import gradio as gr
8
+ import tempfile
9
+ import requests
10
+
11
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
12
+ # 1) Path ke ONNX model β€œΓ—4” (diunduh dari GitHub)
13
+ MODEL_DIR = "model"
14
+ MODEL_X4_PATH = os.path.join(MODEL_DIR, "Real-ESRGAN-x4plus.onnx")
15
+
16
+ # Cek jika model belum ada, maka unduh dari GitHub
17
+ if not os.path.isfile(MODEL_X4_PATH):
18
+ os.makedirs(MODEL_DIR, exist_ok=True)
19
+ model_url = "https://raw.githubusercontent.com/salmanalfarisi11/Upscaler_images/master/model/Real-ESRGAN-x4plus.onnx"
20
+ response = requests.get(model_url)
21
+
22
+ # Jika unduhan berhasil, simpan model
23
+ if response.status_code == 200:
24
+ with open(MODEL_X4_PATH, 'wb') as f:
25
+ f.write(response.content)
26
+ print(f"Model telah diunduh dan disimpan di {MODEL_X4_PATH}")
27
+ else:
28
+ raise FileNotFoundError(f"Model gagal diunduh dari GitHub, status code: {response.status_code}")
29
+
30
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
31
+ # 2) Buat ONNXRuntime session hanya dengan CPU, 2 thread
32
+ sess_opts = ort.SessionOptions()
33
+ sess_opts.intra_op_num_threads = 2
34
+ sess_opts.inter_op_num_threads = 2
35
+
36
+ session_x4 = ort.InferenceSession(MODEL_X4_PATH, sess_options=sess_opts,
37
+ providers=["CPUExecutionProvider"])
38
+
39
+ # Ambil metadata ukuran input tile untuk model Γ—4 (biasanya 128Γ—128)
40
+ input_meta_x4 = session_x4.get_inputs()[0]
41
+ _, _, H_in_x4, W_in_x4 = tuple(input_meta_x4.shape)
42
+ H_in_x4, W_in_x4 = int(H_in_x4), int(W_in_x4)
43
 
44
+ # Cek skala (harusnya 4Γ—)
45
+ dummy = np.zeros((1, 3, H_in_x4, W_in_x4), dtype=np.float32)
46
+ dummy_out = session_x4.run(None, {input_meta_x4.name: dummy})[0]
47
+ _, _, H_out_x4, W_out_x4 = dummy_out.shape
48
+ SCALE_X4 = H_out_x4 // H_in_x4
49
+ if SCALE_X4 != 4:
50
+ raise RuntimeError(f"Model Γ—4 menghasilkan scale = {SCALE_X4}, bukan 4")
51
 
52
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
53
+ # 3) Fungsi util untuk mem‐proses satu tile 128Γ—128 β†’ 512Γ—512
54
+ def run_tile_x4(tile_np: np.ndarray) -> np.ndarray:
55
+ """
56
+ Input: tile_np (128,128,3) float32 ∈ [0,1]
57
+ Output: (512,512,3) float32 ∈ [0,1]
58
+ """
59
+ patch_nchw = np.transpose(tile_np, (2, 0, 1))[None, ...] # β†’ (1,3,128,128)
60
+ out_nchw = session_x4.run(None, {input_meta_x4.name: patch_nchw})[0] # (1,3,512,512)
61
+ out_nchw = np.squeeze(out_nchw, axis=0) # (3,512,512)
62
+ out_hwc = np.transpose(out_nchw, (1, 2, 0)) # (512,512,3)
63
+ return out_hwc # float32 ∈ [0,1]
64
 
65
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
66
+ # 4) Pipeline tile‐based untuk Γ—4 –– mem‐pad, potong, infer, reassemble, crop
67
+ def tile_upscale_x4(input_img: Image.Image):
68
  """
69
+ 1. PILβ†’float32 np ∈ [0,1]
70
+ 2. Pad agar (H,W) kelipatan H_in_x4 (128)
71
+ 3. Bagi menjadi tile (H_in_x4 Γ— W_in_x4)
72
+ 4. run_tile_x4 per tile, simpan ke out_arr
73
+ 5. Crop ke (orig_h*4, orig_w*4)
74
+ 6. Convert ke uint8 PIL, save PNG, return (PIL, filepath)
75
  """
76
+ # 4.1. Convert PIL→float32 [0,1]
77
+ img_rgb = input_img.convert("RGB")
78
+ arr = np.array(img_rgb).astype(np.float32) / 255.0 # (h_orig, w_orig, 3)
79
+ h_orig, w_orig, _ = arr.shape
80
+
81
+ # 4.2. Hitung jumlah tile dan padding
82
+ tiles_h = math.ceil(h_orig / H_in_x4)
83
+ tiles_w = math.ceil(w_orig / W_in_x4)
84
+ pad_h = tiles_h * H_in_x4 - h_orig
85
+ pad_w = tiles_w * W_in_x4 - w_orig
86
+
87
+ # Reflect pad di kanan + bawah
88
+ arr_padded = np.pad(
89
+ arr,
90
+ ((0, pad_h), (0, pad_w), (0, 0)),
91
+ mode="reflect"
92
+ ) # β†’ (tiles_h * 128, tiles_w * 128, 3)
93
+
94
+ # 4.3. Buat array output berukuran (tiles_h*512, tiles_w*512, 3)
95
+ out_h = tiles_h * H_in_x4 * SCALE_X4
96
+ out_w = tiles_w * W_in_x4 * SCALE_X4
97
+ out_arr = np.zeros((out_h, out_w, 3), dtype=np.float32)
98
+
99
+ # 4.4. Loop semua tile
100
+ for i in range(tiles_h):
101
+ for j in range(tiles_w):
102
+ y0 = i * H_in_x4
103
+ x0 = j * W_in_x4
104
+ tile = arr_padded[y0 : y0 + H_in_x4, x0 : x0 + W_in_x4, :] # (128,128,3)
105
+
106
+ up_tile = run_tile_x4(tile) # (512,512,3) float32
107
+
108
+ oy0 = i * H_in_x4 * SCALE_X4
109
+ ox0 = j * W_in_x4 * SCALE_X4
110
+ out_arr[oy0 : oy0 + H_in_x4 * SCALE_X4,
111
+ ox0 : ox0 + W_in_x4 * SCALE_X4, :] = up_tile
112
+
113
+ # 4.5. Crop β†’ (h_orig*4, w_orig*4)
114
+ final_arr = out_arr[0 : h_orig * SCALE_X4, 0 : w_orig * SCALE_X4, :]
115
+ final_arr = np.clip(final_arr, 0.0, 1.0)
116
+ final_uint8 = (final_arr * 255.0).round().astype(np.uint8)
117
+ final_pil = Image.fromarray(final_uint8) # (h_orig*4, w_orig*4)
118
+
119
+ # 4.6. Simpan ke file PNG unik
120
  tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
121
+ final_pil.save(tmp.name, format="PNG")
122
  tmp.close()
123
+ return final_pil, tmp.name
124
+
125
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
126
+ # 5) Fungsi Standard (Γ—4) dan Premium (Γ—8) untuk Gradio
127
+ def standard_upscale(input_img: Image.Image):
128
+ # Hasil ×4 tile→reassemble
129
+ return tile_upscale_x4(input_img)
130
+
131
+ def premium_upscale(input_img: Image.Image):
132
+ """
133
+ - Jalankan pipeline Γ—4 untuk dapat final_4x (PIL)
134
+ - Lalu bicubic‐resize final_4x β†’ 8Γ— resolusi (orig_w*8, orig_h*8)
135
+ - Simpan PNG baru dan return (PIL_8x, filepath)
136
+ """
137
+ # 5.1. Pertama dapatkan output Γ—4
138
+ final_4x, path_4x = tile_upscale_x4(input_img) # final_4x size = (h_orig*4, w_orig*4)
139
 
140
+ # 5.2. Ukuran asli
141
+ w_orig, h_orig = input_img.size
142
+
143
+ # 5.3. Resize bicubic (LANCZOS) dari 4Γ— β†’ 8Γ—
144
+ target_size = (w_orig * 8, h_orig * 8)
145
+ final_8x = final_4x.resize(target_size, resample=Image.LANCZOS)
146
+
147
+ # 5.4. Simpan PNG unik
148
+ tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
149
+ final_8x.save(tmp.name, format="PNG")
150
+ tmp.close()
151
+
152
+ return final_8x, tmp.name
153
+
154
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
155
+ # 6) CSS Kustom agar tombol Premium bergenre β€œemas”
156
+ css = """
157
+ #premium-btn {
158
+ background-color: gold !important;
159
+ color: black !important;
160
+ }
161
+ """
162
+
163
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
164
+ # 7) Bangun Gradio Blocks – 2 tombol berdampingan
165
+ with gr.Blocks(css=css, title="Real-ESRGAN Dual-Mode Upscaler") as demo:
166
  gr.Markdown(
167
+ """
168
+ # Real-ESRGAN Dual-Mode Upscaler
169
+ **Standard Upscale** (Γ—4) atau **Premium Upscale πŸš€** (Γ—8).
170
+ Silakan upload gambar apa saja, kemudian klik tombol yang diinginkan.
171
+ """
172
  )
173
 
174
+ # Baris untuk upload gambar
175
  with gr.Row():
176
+ inp_image = gr.Image(type="pil", label="Upload Source Image")
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
+ # Baris untuk dua tombol
179
+ with gr.Row():
180
+ btn_std = gr.Button("Standard Upscale (Γ—4)", variant="primary", elem_id="std-btn")
181
+ btn_prem = gr.Button("Premium Upscale πŸš€ (Γ—8)", elem_id="premium-btn")
182
+
183
+ # Dua output: preview image & link β€œDownload PNG”
184
+ out_preview = gr.Image(type="pil", label="Upscaled Preview")
185
+ out_download = gr.DownloadButton("⬇️ Download PNG", visible=True)
186
+
187
+ # Hubungkan tombol ke fungsi:
188
+ btn_std.click(fn=standard_upscale, inputs=inp_image, outputs=[out_preview, out_download])
189
+ btn_prem.click(fn=premium_upscale, inputs=inp_image, outputs=[out_preview, out_download])
190
 
191
+ demo.launch(server_name="0.0.0.0", server_port=7860)