ffxbot commited on
Commit
d346aa9
·
verified ·
1 Parent(s): c33220d

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +361 -0
  2. requirements (1).txt +9 -0
app.py ADDED
@@ -0,0 +1,361 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import cv2
4
+ import os
5
+ import time
6
+ import requests
7
+ import subprocess
8
+ import sys
9
+ from PIL import Image
10
+
11
+ # ─── Model Download ───────────────────────────────────────────────────────────
12
+ MODEL_DIR = "weights"
13
+ MODEL_PATH = os.path.join(MODEL_DIR, "RealESRGAN_x4plus.pth")
14
+ MODEL_URL = "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth"
15
+
16
+ def download_model():
17
+ os.makedirs(MODEL_DIR, exist_ok=True)
18
+ if not os.path.exists(MODEL_PATH):
19
+ print("📥 মডেল ডাউনলোড হচ্ছে...")
20
+ r = requests.get(MODEL_URL, stream=True)
21
+ with open(MODEL_PATH, "wb") as f:
22
+ for chunk in r.iter_content(chunk_size=8192):
23
+ f.write(chunk)
24
+ print("✅ মডেল ডাউনলোড সম্পন্ন!")
25
+
26
+ download_model()
27
+
28
+ # ─── Real-ESRGAN Setup ────────────────────────────────────────────────────────
29
+ from basicsr.archs.rrdbnet_arch import RRDBNet
30
+ from realesrgan import RealESRGANer
31
+
32
+ def load_upsampler():
33
+ model = RRDBNet(
34
+ num_in_ch=3, num_out_ch=3,
35
+ num_feat=64, num_block=23, num_grow_ch=32, scale=4
36
+ )
37
+ upsampler = RealESRGANer(
38
+ scale=4,
39
+ model_path=MODEL_PATH,
40
+ model=model,
41
+ tile=256, # tile processing → কম RAM লাগবে
42
+ tile_pad=10,
43
+ pre_pad=0,
44
+ half=False # CPU-safe
45
+ )
46
+ return upsampler
47
+
48
+ print("🔄 মডেল লোড হচ্ছে...")
49
+ upsampler = load_upsampler()
50
+ print("✅ মডেল রেডি!")
51
+
52
+ # ─── Image Analysis ───────────────────────────────────────────────────────────
53
+ def analyze_image(img: Image.Image) -> dict:
54
+ w, h = img.size
55
+ mp = (w * h) / 1_000_000
56
+
57
+ if w >= 3840 or h >= 2160:
58
+ quality_label = "4K বা তার বেশি (Ultra HD)"
59
+ quality_icon = "🟣"
60
+ elif w >= 1920 or h >= 1080:
61
+ quality_label = "1080p Full HD"
62
+ quality_icon = "🟢"
63
+ elif w >= 1280 or h >= 720:
64
+ quality_label = "720p HD"
65
+ quality_icon = "🟡"
66
+ elif w >= 854 or h >= 480:
67
+ quality_label = "480p SD"
68
+ quality_icon = "🟠"
69
+ else:
70
+ quality_label = "লো রেজোলিউশন"
71
+ quality_icon = "🔴"
72
+
73
+ mode_label = {"RGB": "রঙিন (RGB)", "RGBA": "রঙিন + Transparency", "L": "কালো-সাদা"}.get(img.mode, img.mode)
74
+
75
+ return {
76
+ "width": w, "height": h,
77
+ "megapixels": round(mp, 2),
78
+ "quality_label": quality_label,
79
+ "quality_icon": quality_icon,
80
+ "mode": mode_label,
81
+ "target_w": 3840, "target_h": 2160
82
+ }
83
+
84
+ # ─── Main Processing ──────────────────────────────────────────────────────────
85
+ def upscale_to_4k(input_image, progress=gr.Progress(track_tqdm=True)):
86
+ if input_image is None:
87
+ return None, "❌ কোনো ছবি আপলোড করা হয়নি।", "", ""
88
+
89
+ t_start = time.time()
90
+
91
+ # Step 1: Analyze
92
+ yield None, "🔍 **ছবি বিশ্লেষণ হচ্ছে...**", "", "⏳ প্রসেসিং শুরু হয়েছে"
93
+ time.sleep(0.3)
94
+
95
+ pil_img = Image.fromarray(input_image) if isinstance(input_image, np.ndarray) else input_image
96
+ info = analyze_image(pil_img)
97
+
98
+ analysis_text = f"""
99
+ ## 📊 ছবি বিশ্লেষণ ফলাফল
100
+
101
+ | তথ্য | মান |
102
+ |------|-----|
103
+ | {info['quality_icon']} কোয়ালিটি | **{info['quality_label']}** |
104
+ | 📐 বর্তমান রেজোলিউশন | **{info['width']} × {info['height']} px** |
105
+ | 📷 মেগাপিক্সেল | **{info['megapixels']} MP** |
106
+ | 🎨 কালার মোড | **{info['mode']}** |
107
+ | 🎯 টার্গেট রেজোলিউশন | **3840 × 2160 (4K)** |
108
+
109
+ ---
110
+ ⚡ **AI Upscaling শুরু হচ্ছে...**
111
+ """
112
+
113
+ yield None, analysis_text, "", "🔄 AI প্রসেসিং চলছে..."
114
+
115
+ # Step 2: Convert to numpy BGR for ESRGAN
116
+ img_np = np.array(pil_img.convert("RGB"))
117
+ img_bgr = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)
118
+
119
+ # Step 3: Upscale with Real-ESRGAN (4x)
120
+ try:
121
+ output_bgr, _ = upsampler.enhance(img_bgr, outscale=4)
122
+ except Exception as e:
123
+ yield None, f"❌ **এরর:** {str(e)}", "", "❌ ব্যর্থ হয়েছে"
124
+ return
125
+
126
+ # Step 4: Convert back to RGB
127
+ output_rgb = cv2.cvtColor(output_bgr, cv2.COLOR_BGR2RGB)
128
+ output_pil = Image.fromarray(output_rgb)
129
+ out_w, out_h = output_pil.size
130
+
131
+ # Step 5: Crop/pad to exact 4K if needed
132
+ if out_w != 3840 or out_h != 2160:
133
+ output_pil = output_pil.resize((3840, 2160), Image.LANCZOS)
134
+
135
+ t_end = time.time()
136
+ elapsed = t_end - t_start
137
+ mins = int(elapsed // 60)
138
+ secs = int(elapsed % 60)
139
+ time_str = f"{mins} মিনিট {secs} সেকেন্ড" if mins > 0 else f"{secs} সেকেন্ড"
140
+
141
+ # Step 6: Save output
142
+ out_path = "/tmp/4k_output.png"
143
+ output_pil.save(out_path, "PNG", optimize=False)
144
+ file_size_mb = os.path.getsize(out_path) / (1024 * 1024)
145
+
146
+ result_text = f"""
147
+ ## ✅ 4K Upscaling সম্পন্ন!
148
+
149
+ | ফলাফল | মান |
150
+ |--------|-----|
151
+ | 🎯 আউটপুট রেজোলিউশন | **3840 × 2160 (4K Ultra HD)** |
152
+ | 📁 ফাইল সাইজ | **{file_size_mb:.1f} MB** |
153
+ | ⏱️ সময় লেগেছে | **{time_str}** |
154
+ | ✨ আপস্কেল রেশিও | **4× (AI Enhanced)** |
155
+ | 🧠 মডেল | **Real-ESRGAN x4plus** |
156
+
157
+ ---
158
+ 💾 নিচের ছবিতে রাইট ক্লিক করে **"Save Image"** দিয়ে ডাউনলোড করুন
159
+ """
160
+
161
+ time_display = f"✅ {time_str} এ সম্পন্ন | 3840×2160 (4K)"
162
+
163
+ yield np.array(output_pil), result_text, out_path, time_display
164
+
165
+
166
+ # ─── Custom CSS ───────────────────────────────────────────────────────────────
167
+ CSS = """
168
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&display=swap');
169
+
170
+ * { font-family: 'Inter', sans-serif; box-sizing: border-box; }
171
+
172
+ body, .gradio-container {
173
+ background: #0a0a0f !important;
174
+ color: #e8e8f0 !important;
175
+ }
176
+
177
+ .gradio-container {
178
+ max-width: 1100px !important;
179
+ margin: 0 auto !important;
180
+ padding: 20px !important;
181
+ }
182
+
183
+ #header {
184
+ text-align: center;
185
+ padding: 40px 20px 30px;
186
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
187
+ border-radius: 20px;
188
+ margin-bottom: 24px;
189
+ border: 1px solid #2a2a4a;
190
+ }
191
+
192
+ #header h1 {
193
+ font-size: 2.8rem;
194
+ font-weight: 700;
195
+ background: linear-gradient(90deg, #00d4ff, #7b2ff7, #ff6b6b);
196
+ -webkit-background-clip: text;
197
+ -webkit-text-fill-color: transparent;
198
+ margin: 0 0 10px;
199
+ }
200
+
201
+ #header p {
202
+ color: #8888aa;
203
+ font-size: 1.05rem;
204
+ margin: 0;
205
+ }
206
+
207
+ .badge-row {
208
+ display: flex;
209
+ justify-content: center;
210
+ gap: 12px;
211
+ flex-wrap: wrap;
212
+ margin-top: 16px;
213
+ }
214
+
215
+ .badge {
216
+ background: rgba(0,212,255,0.1);
217
+ border: 1px solid rgba(0,212,255,0.3);
218
+ color: #00d4ff;
219
+ padding: 5px 14px;
220
+ border-radius: 20px;
221
+ font-size: 0.82rem;
222
+ font-weight: 600;
223
+ }
224
+
225
+ #timer-box {
226
+ background: linear-gradient(135deg, #1a1a2e, #0f1923);
227
+ border: 1px solid #2a3a5a;
228
+ border-radius: 14px;
229
+ padding: 16px 24px;
230
+ text-align: center;
231
+ font-size: 1.1rem;
232
+ font-weight: 600;
233
+ color: #00d4ff;
234
+ margin-bottom: 16px;
235
+ min-height: 54px;
236
+ display: flex;
237
+ align-items: center;
238
+ justify-content: center;
239
+ }
240
+
241
+ .upload-zone label {
242
+ font-size: 1rem !important;
243
+ font-weight: 600 !important;
244
+ color: #aaaacc !important;
245
+ }
246
+
247
+ #upscale-btn {
248
+ background: linear-gradient(135deg, #7b2ff7, #00d4ff) !important;
249
+ border: none !important;
250
+ color: white !important;
251
+ font-size: 1.1rem !important;
252
+ font-weight: 700 !important;
253
+ padding: 14px 32px !important;
254
+ border-radius: 12px !important;
255
+ cursor: pointer !important;
256
+ transition: all 0.3s !important;
257
+ width: 100% !important;
258
+ letter-spacing: 0.5px !important;
259
+ }
260
+
261
+ #upscale-btn:hover {
262
+ transform: translateY(-2px) !important;
263
+ box-shadow: 0 8px 30px rgba(123,47,247,0.5) !important;
264
+ }
265
+
266
+ .panel {
267
+ background: #111122 !important;
268
+ border: 1px solid #2a2a4a !important;
269
+ border-radius: 16px !important;
270
+ padding: 20px !important;
271
+ }
272
+
273
+ .result-markdown {
274
+ background: #0d0d1f !important;
275
+ border-radius: 12px;
276
+ padding: 16px;
277
+ }
278
+
279
+ footer { display: none !important; }
280
+ """
281
+
282
+ # ─── UI Layout ────────────────────────────────────────────────────────────────
283
+ with gr.Blocks(css=CSS, title="4K AI Upscaler", theme=gr.themes.Base()) as demo:
284
+
285
+ gr.HTML("""
286
+ <div id="header">
287
+ <h1>🚀 4K AI Upscaler</h1>
288
+ <p>যেকোনো ছবি আপলোড করুন — AI দিয়ে ৪K Ultra HD তে রূপান্তর করুন</p>
289
+ <div class="badge-row">
290
+ <span class="badge">⚡ Real-ESRGAN</span>
291
+ <span class="badge">🎯 3840×2160 Output</span>
292
+ <span class="badge">🧠 AI Powered</span>
293
+ <span class="badge">🆓 সম্পূর্ণ বিনামূল্যে</span>
294
+ </div>
295
+ </div>
296
+ """)
297
+
298
+ timer_display = gr.HTML(
299
+ '<div id="timer-box">⏳ ছবি আপলোড করুন এবং বাটন চাপুন</div>',
300
+ elem_id="timer-container"
301
+ )
302
+
303
+ with gr.Row():
304
+ with gr.Column(scale=1, elem_classes="panel"):
305
+ input_img = gr.Image(
306
+ label="📤 ছবি আপলোড করুন",
307
+ type="numpy",
308
+ sources=["upload", "clipboard"],
309
+ height=320,
310
+ elem_classes="upload-zone"
311
+ )
312
+ upscale_btn = gr.Button(
313
+ "✨ 4K তে রূপান্তর করুন",
314
+ elem_id="upscale-btn",
315
+ variant="primary"
316
+ )
317
+
318
+ with gr.Column(scale=1, elem_classes="panel"):
319
+ output_img = gr.Image(
320
+ label="📥 4K আউটপুট",
321
+ type="numpy",
322
+ height=320,
323
+ interactive=False
324
+ )
325
+
326
+ with gr.Row():
327
+ with gr.Column():
328
+ result_md = gr.Markdown(
329
+ value="*এখানে বিশ্লেষণ ও ফলাফল দেখাবে...*",
330
+ elem_classes="result-markdown"
331
+ )
332
+ with gr.Column():
333
+ download_file = gr.File(
334
+ label="💾 4K ফাইল ডাউনলোড করুন",
335
+ interactive=False
336
+ )
337
+
338
+ gr.HTML("""
339
+ <div style="text-align:center; padding: 20px; color: #555577; font-size:0.85rem;">
340
+ Powered by Real-ESRGAN • Hosted on Hugging Face Spaces 🤗
341
+ </div>
342
+ """)
343
+
344
+ # ── Wire up ──
345
+ def run(img):
346
+ last = None, "", "", ""
347
+ gen = upscale_to_4k(img)
348
+ for out_img, md, path, timer in gen:
349
+ last = (out_img, md, path, timer)
350
+ timer_html = f'<div id="timer-box">{timer}</div>'
351
+ yield out_img, md, path, timer_html
352
+ return
353
+
354
+ upscale_btn.click(
355
+ fn=run,
356
+ inputs=[input_img],
357
+ outputs=[output_img, result_md, download_file, timer_display]
358
+ )
359
+
360
+ if __name__ == "__main__":
361
+ demo.launch()
requirements (1).txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ gradio==4.44.0
2
+ Pillow==10.4.0
3
+ numpy==1.26.4
4
+ opencv-python-headless==4.10.0.84
5
+ basicsr==1.4.2
6
+ realesrgan==0.3.0
7
+ torch==2.2.2
8
+ torchvision==0.17.2
9
+ requests==2.32.3