| import gradio as gr |
| import numpy as np |
| import cv2 |
| import os |
| import time |
| import requests |
| import sys |
| from PIL import Image |
| |
| import torchvision.transforms.functional |
| sys.modules['torchvision.transforms.functional_tensor'] = torchvision.transforms.functional |
| |
| |
| MODEL_DIR = "weights" |
| MODEL_PATH = os.path.join(MODEL_DIR, "RealESRGAN_x4plus.pth") |
| MODEL_URL = "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth" |
| def download_model(): |
| os.makedirs(MODEL_DIR, exist_ok=True) |
| if not os.path.exists(MODEL_PATH): |
| print("📥 মডেল ডাউনলোড হচ্ছে...") |
| r = requests.get(MODEL_URL, stream=True) |
| with open(MODEL_PATH, "wb") as f: |
| for chunk in r.iter_content(chunk_size=8192): |
| f.write(chunk) |
| print("✅ মডেল ডাউনলোড সম্পন্ন!") |
| download_model() |
| |
| from basicsr.archs.rrdbnet_arch import RRDBNet |
| from realesrgan import RealESRGANer |
| def load_upsampler(): |
| model = RRDBNet( |
| num_in_ch=3, num_out_ch=3, |
| num_feat=64, num_block=23, num_grow_ch=32, scale=4 |
| ) |
| upsampler = RealESRGANer( |
| scale=4, |
| model_path=MODEL_PATH, |
| model=model, |
| tile=128, |
| tile_pad=10, |
| pre_pad=0, |
| half=False |
| ) |
| return upsampler |
| print("🔄 মডেল লোড হচ্ছে...") |
| upsampler = load_upsampler() |
| print("✅ মডেল রেডি!") |
| |
| def analyze_image(img: Image.Image) -> dict: |
| w, h = img.size |
| mp = (w * h) / 1_000_000 |
| if w >= 3840 or h >= 2160: |
| quality_label = "4K বা তার বেশি (Ultra HD)" |
| quality_icon = "🟣" |
| elif w >= 1920 or h >= 1080: |
| quality_label = "1080p Full HD" |
| quality_icon = "🟢" |
| elif w >= 1280 or h >= 720: |
| quality_label = "720p HD" |
| quality_icon = "🟡" |
| elif w >= 854 or h >= 480: |
| quality_label = "480p SD" |
| quality_icon = "🟠" |
| else: |
| quality_label = "লো রেজোলিউশন" |
| quality_icon = "🔴" |
| mode_label = {"RGB": "রঙিন (RGB)", "RGBA": "রঙিন + Transparency", "L": "কালো-সাদা"}.get(img.mode, img.mode) |
| return { |
| "width": w, "height": h, |
| "megapixels": round(mp, 2), |
| "quality_label": quality_label, |
| "quality_icon": quality_icon, |
| "mode": mode_label, |
| "target_w": 3840, "target_h": 2160 |
| } |
| |
| def upscale_to_4k(pil_img): |
| if pil_img is None: |
| yield None, "❌ কোনো ছবি আপলোড করা হয়নি।", None, "" |
| return |
| t_start = time.time() |
| yield None, "🔍 **ছবি বিশ্লেষণ হচ্ছে...**", None, "⏳ প্রসেসিং শুরু হয়েছে" |
| time.sleep(0.3) |
| pil_img = pil_img.convert("RGB") |
| info = analyze_image(pil_img) |
| analysis_text = f""" |
| ## 📊 ছবি বিশ্লেষণ ফলাফল |
| |
| | তথ্য | মান | |
| | :--- | :--- | |
| | {info['quality_icon']} বর্তমান কোয়ালিটি | **{info['quality_label']}** | |
| | 📐 বর্তমান রেজোলিউশন | **{info['width']} × {info['height']} px** | |
| | 📷 মেগাপিক্সেল | **{info['megapixels']} MP** | |
| | 🎯 টার্গেট রেজোলিউশন | **3840 × 2160 (4K)** | |
| |
| --- |
| ⚡ **AI Upscaling শুরু হচ্ছে (১-২ মিনিট সময় দিন)...** |
| """ |
| yield None, analysis_text, None, "🔄 AI প্রসেসিং চলছে..." |
| img_np = np.array(pil_img) |
| img_bgr = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR) |
| try: |
| output_bgr, _ = upsampler.enhance(img_bgr, outscale=4) |
| except Exception as e: |
| yield None, f"❌ **এরর:** সার্ভার ওভারলোড হয়েছে, আবার চেষ্টা করুন।", None, "❌ ব্যর্থ হয়েছে" |
| return |
| output_rgb = cv2.cvtColor(output_bgr, cv2.COLOR_BGR2RGB) |
| output_pil = Image.fromarray(output_rgb) |
| out_w, out_h = output_pil.size |
| if out_w != 3840 or out_h != 2160: |
| output_pil = output_pil.resize((3840, 2160), Image.LANCZOS) |
| t_end = time.time() |
| elapsed = t_end - t_start |
| mins = int(elapsed // 60) |
| secs = int(elapsed % 60) |
| time_str = f"{mins} মিনিট {secs} সেকেন্ড" if mins > 0 else f"{secs} সেকেন্ড" |
| out_path = "/tmp/4k_output.png" |
| output_pil.save(out_path, "PNG", optimize=False) |
| file_size_mb = os.path.getsize(out_path) / (1024 * 1024) |
| result_text = f""" |
| ## ✅ 4K Upscaling সম্পন্ন! |
| |
| | ফলাফল | মান | |
| | :--- | :--- | |
| | 🎯 আউটপুট রেজোলিউশন | **3840 × 2160 (4K Ultra HD)** | |
| | 📁 ফাইল সাইজ | **{file_size_mb:.1f} MB** | |
| | ⏱️ সময় লেগেছে | **{time_str}** | |
| | ✨ আপস্কেল রেশিও | **অটোম্যাটিক 4K এনালাইসিস** | |
| | 🧠 মডেল | **Real-ESRGAN x4plus** | |
| |
| --- |
| 💾 নিচের ছবিতে রাইট ক্লিক করে **"Save Image"** দিয়ে ডাউনলোড করুন অথবা ডাউনলোড বাটনে চাপুন। |
| """ |
| time_display = f"✅ {time_str} এ সম্পন্ন | 3840×2160 (4K)" |
| yield output_pil, result_text, out_path, time_display |
| |
| CSS = """ |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&display=swap'); |
| * { font-family: 'Inter', sans-serif; box-sizing: border-box; } |
| body, .gradio-container { |
| background: #0a0a0f !important; |
| color: #e8e8f0 !important; |
| } |
| .gradio-container { |
| max-width: 1100px !important; |
| margin: 0 auto !important; |
| padding: 20px !important; |
| } |
| #header { |
| text-align: center; |
| padding: 40px 20px 30px; |
| background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%); |
| border-radius: 20px; |
| margin-bottom: 24px; |
| border: 1px solid #2a2a4a; |
| } |
| #header h1 { |
| font-size: 2.8rem; |
| font-weight: 700; |
| background: linear-gradient(90deg, #00d4ff, #7b2ff7, #ff6b6b); |
| -webkit-background-clip: text; |
| -webkit-text-fill-color: transparent; |
| margin: 0 0 10px; |
| } |
| #header p { |
| color: #8888aa; |
| font-size: 1.05rem; |
| margin: 0; |
| } |
| .badge-row { |
| display: flex; |
| justify-content: center; |
| gap: 12px; |
| flex-wrap: wrap; |
| margin-top: 16px; |
| } |
| .badge { |
| background: rgba(0,212,255,0.1); |
| border: 1px solid rgba(0,212,255,0.3); |
| color: #00d4ff; |
| padding: 5px 14px; |
| border-radius: 20px; |
| font-size: 0.82rem; |
| font-weight: 600; |
| } |
| #timer-box { |
| background: linear-gradient(135deg, #1a1a2e, #0f1923); |
| border: 1px solid #2a3a5a; |
| border-radius: 14px; |
| padding: 16px 24px; |
| text-align: center; |
| font-size: 1.1rem; |
| font-weight: 600; |
| color: #00d4ff; |
| margin-bottom: 16px; |
| min-height: 54px; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| } |
| .upload-zone label { |
| font-size: 1rem !important; |
| font-weight: 600 !important; |
| color: #aaaacc !important; |
| } |
| #upscale-btn { |
| background: linear-gradient(135deg, #7b2ff7, #00d4ff) !important; |
| border: none !important; |
| color: white !important; |
| font-size: 1.1rem !important; |
| font-weight: 700 !important; |
| padding: 14px 32px !important; |
| border-radius: 12px !important; |
| cursor: pointer !important; |
| transition: all 0.3s !important; |
| width: 100% !important; |
| letter-spacing: 0.5px !important; |
| } |
| #upscale-btn:hover { |
| transform: translateY(-2px) !important; |
| box-shadow: 0 8px 30px rgba(123,47,247,0.5) !important; |
| } |
| .panel { |
| background: #111122 !important; |
| border: 1px solid #2a2a4a !important; |
| border-radius: 16px !important; |
| padding: 20px !important; |
| } |
| .result-markdown { |
| background: #0d0d1f !important; |
| border-radius: 12px; |
| padding: 16px; |
| } |
| footer { display: none !important; } |
| """ |
| |
| with gr.Blocks(css=CSS, title="4K AI Upscaler") as demo: |
| gr.HTML(""" |
| <div id="header"> |
| <h1>🚀 4K AI Upscaler</h1> |
| <p>যেকোনো ছবি আপলোড করুন — AI স্বয়ংক্রিয়ভাবে বিশ্লেষণ করে ৪K Ultra HD তে রূপান্তর করবে</p> |
| <div class="badge-row"> |
| <span class="badge">⚡ Real-ESRGAN</span> |
| <span class="badge">🎯 3840×2160 Output</span> |
| <span class="badge">🧠 AI Powered</span> |
| <span class="badge">🆓 সম্পূর্ণ বিনামূল্যে</span> |
| </div> |
| </div> |
| """) |
| timer_display = gr.HTML( |
| '<div id="timer-box">⏳ ছবি আপলোড করুন এবং বাটন চাপুন</div>', |
| elem_id="timer-container" |
| ) |
| with gr.Row(): |
| with gr.Column(scale=1, elem_classes="panel"): |
| input_img = gr.Image( |
| label="📤 ছবি আপলোড করুন", |
| type="pil", |
| sources=["upload", "clipboard"], |
| height=320, |
| elem_classes="upload-zone" |
| ) |
| upscale_btn = gr.Button( |
| "✨ 4K তে রূপান্তর করুন", |
| elem_id="upscale-btn", |
| variant="primary" |
| ) |
| with gr.Column(scale=1, elem_classes="panel"): |
| output_img = gr.Image( |
| label="📥 4K আউটপুট", |
| type="pil", |
| height=320, |
| interactive=False |
| ) |
| with gr.Row(): |
| with gr.Column(): |
| result_md = gr.Markdown( |
| value="*এখানে বিশ্লেষণ ও ফলাফল দেখাবে...*", |
| elem_classes="result-markdown" |
| ) |
| with gr.Column(): |
| download_file = gr.File( |
| label="💾 4K ফাইল ডাউনলোড করুন", |
| interactive=False |
| ) |
| gr.HTML(""" |
| <div style="text-align:center; padding: 20px; color: #555577; font-size:0.85rem;"> |
| Powered by Real-ESRGAN • Hosted on Hugging Face Spaces 🤗 |
| </div> |
| """) |
| def run(img_pil): |
| last = None, "", None, "" |
| gen = upscale_to_4k(img_pil) |
| for out_img, md, path, timer in gen: |
| last = (out_img, md, path, timer) |
| timer_html = f'<div id="timer-box">{timer}</div>' |
| yield out_img, md, path, timer_html |
| return |
| upscale_btn.click( |
| fn=run, |
| inputs=[input_img], |
| outputs=[output_img, result_md, download_file, timer_display] |
| ) |
| if __name__ == "__main__": |
| demo.queue().launch() |