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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -175
app.py CHANGED
@@ -1,191 +1,68 @@
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)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()