salman555 commited on
Commit
097f519
Β·
verified Β·
1 Parent(s): ca46a82

Upload 6 files

Browse files
Files changed (6) hide show
  1. .gitattributes +1 -0
  2. .gitignore +15 -0
  3. LICENSE +22 -0
  4. README.md +142 -0
  5. app.py +184 -0
  6. requirements.txt +4 -0
.gitattributes ADDED
@@ -0,0 +1 @@
 
 
1
+ demo.png filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Ignore Python bytecode files
2
+ __pycache__/
3
+ *.py[cod]
4
+
5
+ # Ignore virtual environments
6
+ venv/
7
+ .venv/
8
+
9
+ # Ignore API keys and configuration files
10
+ .env
11
+
12
+ # Ignore model files and other large files
13
+ model/
14
+
15
+
LICENSE ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Salman Alfarisi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
README.md ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Real-ESRGAN Dual-Mode Image Upscaler
3
+ emoji: πŸ–ΌοΈ
4
+ colorFrom: blue
5
+ colorTo: green
6
+ sdk: gradio
7
+ sdk_version: 5.31.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ ---
12
+
13
+ # πŸ–ΌοΈ Real-ESRGAN Dual-Mode Image Upscaler
14
+
15
+ A lightweight Gradio web app to upscale any image using the Real-ESRGAN model. Simply upload your photo, choose either **Standard Upscale** (Γ—4) or **Premium Upscale** (Γ—8), and download the upscaled image.
16
+
17
+
18
+ ---
19
+
20
+ ## πŸ“‘ Table of Contents
21
+
22
+ 1. [Features](#features)
23
+ 2. [Project Structure](#project-structure)
24
+ 3. [Prerequisites](#prerequisites)
25
+ 4. [Installation](#installation)
26
+ 5. [Running Locally](#running-locally)
27
+ 6. [Usage](#usage)
28
+ 7. [Contributing](#contributing)
29
+ 8. [License](#license)
30
+ 9. [Author & Credits](#author--credits)
31
+
32
+ ---
33
+
34
+ ## ✨ Features
35
+
36
+ - **Standard Upscale (Γ—4)**
37
+ Enhance image resolution by 4x for clearer and larger images.
38
+
39
+ - **Premium Upscale (Γ—8)**
40
+ Upscales first to 4x and then resizes using bicubic interpolation for even higher resolution (8x).
41
+
42
+ - **Live Preview**
43
+ See your original and upscaled images side by side before downloading.
44
+
45
+ - **Instant Download**
46
+ Export the upscaled image as a PNG and use it immediately.
47
+
48
+
49
+
50
+ ---
51
+
52
+
53
+ ## πŸ“ Project Structure
54
+
55
+ ```
56
+ upscale-project/
57
+ β”œβ”€β”€ model/
58
+ β”‚ └── Real-ESRGAN-x4plus.onnx # ONNX model for upscaling
59
+ β”œβ”€β”€ app.py # Main application file
60
+ β”œβ”€β”€ requirements.txt # List of Python dependencies
61
+ β”œβ”€β”€ .gitignore # Git ignore file to exclude unnecessary files
62
+ β”œβ”€β”€ LICENSE # License file for the project
63
+ └── README.md # Project documentation
64
+ ```
65
+
66
+ ---
67
+
68
+
69
+ ---
70
+
71
+ ## βš™οΈ Prerequisites
72
+
73
+ - Python 3.10 or higher
74
+ - `git`
75
+ - A terminal / command prompt
76
+
77
+ ---
78
+
79
+ ## πŸ”§ Installation
80
+
81
+ 1. Clone this repository:
82
+
83
+ ```bash
84
+ git clone https://github.com/salmanalfarisi11/Upscaler_images.git
85
+ cd Upscaler_images
86
+ ```
87
+
88
+ 2. Create and activate a virtual environment:
89
+
90
+ ```bash
91
+ python -m venv .venv
92
+ source .venv/bin/activate # Linux/macOS
93
+ .venv\Scripts\activate # Windows
94
+ ```
95
+
96
+ 3. Install dependencies:
97
+
98
+ ```bash
99
+ pip install -r requirements.txt
100
+ ```
101
+
102
+ ## πŸš€ Running Locally
103
+
104
+ Launch the app on your machine:
105
+ ```bash
106
+ python app.py
107
+ ```
108
+ By default, it will start on http://127.0.0.1:7860/. Open that URL in your browser to access the interface.
109
+
110
+ ## 🎯 Usage
111
+
112
+ 1. **Upload Photo** via the left panel.
113
+ 2. **Choose a Mode**:
114
+ - Click **Standard Upscale (Γ—4)** for a 4x resolution increase.
115
+ - Click **Premium Upscale (Γ—8)** for an 8x resolution increase.
116
+ 3. Preview your result on the right side.
117
+ 4. Click **Download PNG** to save the upscaled image.
118
+
119
+
120
+ ## 🀝 Contributing
121
+ Contributions, bug reports, and feature requests are welcome! Feel free to open an issue or submit a pull request.
122
+
123
+
124
+ ## πŸ“„ License
125
+
126
+ This project is licensed under the [MIT License](LICENSE).
127
+
128
+ ---
129
+
130
+ ## πŸ–‹οΈ Author & Credits
131
+
132
+ Developed by **[Salman Alfarisi](https://github.com/salmanalfarisi11)** Β© 2025
133
+ - GitHub: [salmanalfarisi11](https://github.com/salmanalfarisi11)
134
+ - LinkedIn: [salmanalfarisi11](https://linkedin.com/in/salmanalfarisi11)
135
+ - Instagram: [faris.salman111](https://instagram.com/faris.salman111)
136
+
137
+ Built with ❀️ and Gradio
138
+ Feel free to ⭐ the repo and share feedback!
139
+
140
+ ## Acknowledgements
141
+ This project uses the Real-ESRGAN model developed by Xintao Wang.
142
+ The model is available under the BSD 3-Clause License.
app.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ import numpy as np
4
+ import onnxruntime as ort
5
+ from PIL import Image
6
+ import gradio as gr
7
+ import tempfile
8
+
9
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
10
+ # 1) Path ke ONNX model "Γ—4"
11
+ MODEL_DIR = "model"
12
+ MODEL_X4_PATH = os.path.join(MODEL_DIR, "Real-ESRGAN-x4plus.onnx")
13
+
14
+ # Cek apakah model sudah ada, jika tidak, unduh dari GitHub
15
+ if not os.path.isfile(MODEL_X4_PATH):
16
+ os.makedirs(MODEL_DIR, exist_ok=True)
17
+ model_url = "https://raw.githubusercontent.com/salmanalfarisi11/Upscaler_images/master/model/Real-ESRGAN-x4plus.onnx" # Raw GitHub URL
18
+ response = requests.get(model_url)
19
+ with open(MODEL_X4_PATH, 'wb') as f:
20
+ f.write(response.content)
21
+ print(f"Model downloaded to {MODEL_X4_PATH}")
22
+
23
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
24
+ # 2) Buat ONNXRuntime session hanya dengan CPU, 2 thread
25
+ sess_opts = ort.SessionOptions()
26
+ sess_opts.intra_op_num_threads = 2
27
+ sess_opts.inter_op_num_threads = 2
28
+
29
+ session_x4 = ort.InferenceSession(MODEL_X4_PATH, sess_options=sess_opts,
30
+ providers=["CPUExecutionProvider"])
31
+
32
+ # Ambil metadata ukuran input tile untuk model Γ—4 (biasanya 128Γ—128)
33
+ input_meta_x4 = session_x4.get_inputs()[0]
34
+ _, _, H_in_x4, W_in_x4 = tuple(input_meta_x4.shape)
35
+ H_in_x4, W_in_x4 = int(H_in_x4), int(W_in_x4)
36
+
37
+ # Cek skala (harusnya 4Γ—)
38
+ dummy = np.zeros((1, 3, H_in_x4, W_in_x4), dtype=np.float32)
39
+ dummy_out = session_x4.run(None, {input_meta_x4.name: dummy})[0]
40
+ _, _, H_out_x4, W_out_x4 = dummy_out.shape
41
+ SCALE_X4 = H_out_x4 // H_in_x4
42
+ if SCALE_X4 != 4:
43
+ raise RuntimeError(f"Model Γ—4 menghasilkan scale = {SCALE_X4}, bukan 4")
44
+
45
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
46
+ # 3) Fungsi util untuk mem‐proses satu tile 128Γ—128 β†’ 512Γ—512
47
+ def run_tile_x4(tile_np: np.ndarray) -> np.ndarray:
48
+ """
49
+ Input: tile_np (128,128,3) float32 ∈ [0,1]
50
+ Output: (512,512,3) float32 ∈ [0,1]
51
+ """
52
+ patch_nchw = np.transpose(tile_np, (2, 0, 1))[None, ...] # β†’ (1,3,128,128)
53
+ out_nchw = session_x4.run(None, {input_meta_x4.name: patch_nchw})[0] # (1,3,512,512)
54
+ out_nchw = np.squeeze(out_nchw, axis=0) # (3,512,512)
55
+ out_hwc = np.transpose(out_nchw, (1, 2, 0)) # (512,512,3)
56
+ return out_hwc # float32 ∈ [0,1]
57
+
58
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
59
+ # 4) Pipeline tile‐based untuk Γ—4 –– mem‐pad, potong, infer, reassemble, crop
60
+ def tile_upscale_x4(input_img: Image.Image):
61
+ """
62
+ 1. PILβ†’float32 np ∈ [0,1]
63
+ 2. Pad agar (H,W) kelipatan H_in_x4 (128)
64
+ 3. Bagi menjadi tile (H_in_x4 Γ— W_in_x4)
65
+ 4. run_tile_x4 per tile, simpan ke out_arr
66
+ 5. Crop ke (orig_h*4, orig_w*4)
67
+ 6. Convert ke uint8 PIL, save PNG, return (PIL, filepath)
68
+ """
69
+ # 4.1. Convert PIL→float32 [0,1]
70
+ img_rgb = input_img.convert("RGB")
71
+ arr = np.array(img_rgb).astype(np.float32) / 255.0 # (h_orig, w_orig, 3)
72
+ h_orig, w_orig, _ = arr.shape
73
+
74
+ # 4.2. Hitung jumlah tile dan padding
75
+ tiles_h = math.ceil(h_orig / H_in_x4)
76
+ tiles_w = math.ceil(w_orig / W_in_x4)
77
+ pad_h = tiles_h * H_in_x4 - h_orig
78
+ pad_w = tiles_w * W_in_x4 - w_orig
79
+
80
+ # Reflect pad di kanan + bawah
81
+ arr_padded = np.pad(
82
+ arr,
83
+ ((0, pad_h), (0, pad_w), (0, 0)),
84
+ mode="reflect"
85
+ ) # β†’ (tiles_h * 128, tiles_w * 128, 3)
86
+
87
+ # 4.3. Buat array output berukuran (tiles_h*512, tiles_w*512, 3)
88
+ out_h = tiles_h * H_in_x4 * SCALE_X4
89
+ out_w = tiles_w * W_in_x4 * SCALE_X4
90
+ out_arr = np.zeros((out_h, out_w, 3), dtype=np.float32)
91
+
92
+ # 4.4. Loop semua tile
93
+ for i in range(tiles_h):
94
+ for j in range(tiles_w):
95
+ y0 = i * H_in_x4
96
+ x0 = j * W_in_x4
97
+ tile = arr_padded[y0 : y0 + H_in_x4, x0 : x0 + W_in_x4, :] # (128,128,3)
98
+
99
+ up_tile = run_tile_x4(tile) # (512,512,3) float32
100
+
101
+ oy0 = i * H_in_x4 * SCALE_X4
102
+ ox0 = j * W_in_x4 * SCALE_X4
103
+ out_arr[oy0 : oy0 + H_in_x4 * SCALE_X4,
104
+ ox0 : ox0 + W_in_x4 * SCALE_X4, :] = up_tile
105
+
106
+ # 4.5. Crop β†’ (h_orig*4, w_orig*4)
107
+ final_arr = out_arr[0 : h_orig * SCALE_X4, 0 : w_orig * SCALE_X4, :]
108
+ final_arr = np.clip(final_arr, 0.0, 1.0)
109
+ final_uint8 = (final_arr * 255.0).round().astype(np.uint8)
110
+ final_pil = Image.fromarray(final_uint8) # (h_orig*4, w_orig*4)
111
+
112
+ # 4.6. Simpan ke file PNG unik
113
+ tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
114
+ final_pil.save(tmp.name, format="PNG")
115
+ tmp.close()
116
+ return final_pil, tmp.name
117
+
118
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
119
+ # 5) Fungsi Standard (Γ—4) dan Premium (Γ—8) untuk Gradio
120
+ def standard_upscale(input_img: Image.Image):
121
+ # Hasil ×4 tile→reassemble
122
+ return tile_upscale_x4(input_img)
123
+
124
+ def premium_upscale(input_img: Image.Image):
125
+ """
126
+ - Jalankan pipeline Γ—4 untuk dapat final_4x (PIL)
127
+ - Lalu bicubic‐resize final_4x β†’ 8Γ— resolusi (orig_w*8, orig_h*8)
128
+ - Simpan PNG baru dan return (PIL_8x, filepath)
129
+ """
130
+ # 5.1. Pertama dapatkan output Γ—4
131
+ final_4x, path_4x = tile_upscale_x4(input_img) # final_4x size = (h_orig*4, w_orig*4)
132
+
133
+ # 5.2. Ukuran asli
134
+ w_orig, h_orig = input_img.size
135
+
136
+ # 5.3. Resize bicubic (LANCZOS) dari 4Γ— β†’ 8Γ—
137
+ target_size = (w_orig * 8, h_orig * 8)
138
+ final_8x = final_4x.resize(target_size, resample=Image.LANCZOS)
139
+
140
+ # 5.4. Simpan PNG unik
141
+ tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
142
+ final_8x.save(tmp.name, format="PNG")
143
+ tmp.close()
144
+
145
+ return final_8x, tmp.name
146
+
147
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
148
+ # 6) CSS Kustom agar tombol Premium bergenre β€œemas”
149
+ css = """
150
+ #premium-btn {
151
+ background-color: gold !important;
152
+ color: black !important;
153
+ }
154
+ """
155
+
156
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
157
+ # 7) Bangun Gradio Blocks – 2 tombol berdampingan
158
+ with gr.Blocks(css=css, title="Real-ESRGAN Dual-Mode Upscaler") as demo:
159
+ gr.Markdown(
160
+ """
161
+ # Real-ESRGAN Dual-Mode Upscaler
162
+ **Standard Upscale** (Γ—4) atau **Premium Upscale πŸš€** (Γ—8).
163
+ Silakan upload gambar apa saja, kemudian klik tombol yang diinginkan.
164
+ """
165
+ )
166
+
167
+ # Baris untuk upload gambar
168
+ with gr.Row():
169
+ inp_image = gr.Image(type="pil", label="Upload Source Image")
170
+
171
+ # Baris untuk dua tombol
172
+ with gr.Row():
173
+ btn_std = gr.Button("Standard Upscale (Γ—4)", variant="primary", elem_id="std-btn")
174
+ btn_prem = gr.Button("Premium Upscale πŸš€ (Γ—8)", elem_id="premium-btn")
175
+
176
+ # Dua output: preview image & link β€œDownload PNG”
177
+ out_preview = gr.Image(type="pil", label="Upscaled Preview")
178
+ out_download = gr.DownloadButton("⬇️ Download PNG", visible=True)
179
+
180
+ # Hubungkan tombol ke fungsi:
181
+ btn_std.click(fn=standard_upscale, inputs=inp_image, outputs=[out_preview, out_download])
182
+ btn_prem.click(fn=premium_upscale, inputs=inp_image, outputs=[out_preview, out_download])
183
+
184
+ demo.launch(server_name="0.0.0.0", server_port=7860)
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ onnxruntime # ONNX inference engine (CPU)
2
+ numpy # Array manipulation
3
+ Pillow # Image I/O
4
+ gradio>=3.0 # Web UI