| import sys |
| import torchvision.transforms.functional as F |
|
|
| |
| sys.modules['torchvision.transforms.functional_tensor'] = F |
|
|
| import os |
| import gradio as gr |
| |
|
|
| import os |
|
|
| import gradio as gr |
| import numpy as np |
| import torch |
| from PIL import Image |
| from realesrgan import RealESRGANer |
| from basicsr.archs.rrdbnet_arch import RRDBNet |
|
|
| |
| def load_upsampler(): |
| model = RRDBNet( |
| num_in_ch=3, num_out_ch=3, |
| num_feat=64, num_block=6, num_grow_ch=32, |
| scale=4 |
| ) |
| upsampler = RealESRGANer( |
| scale=4, |
| model_path="models/RealESRGAN_x4plus_anime_6B.pth", |
| model=model, |
| tile=256, tile_pad=10, pre_pad=0, half=False |
| ) |
| return upsampler |
|
|
| print("Loading model...") |
| upsampler = load_upsampler() |
| print("Model ready β
") |
|
|
| def enhance(image, scale): |
| if image is None: |
| return None, "β οΈ No image uploaded." |
| |
| scale = int(scale) if scale in [2, 4] else 4 |
| |
| max_side = 256 |
| w, h = image.size |
| if max(w, h) > max_side * 2: |
| ratio = (max_side * 2) / max(w, h) |
| image = image.resize((int(w * ratio), int(h * ratio)), Image.LANCZOS) |
| upsampler.scale = scale |
| img_np = np.array(image) |
| try: |
| output, _ = upsampler.enhance(img_np, outscale=scale) |
| except RuntimeError as e: |
| return None, f"Error: {str(e)}" |
| result = Image.fromarray(output) |
| orig_w, orig_h = image.size |
| new_w, new_h = result.size |
| info = f"β
Original: {orig_w}Γ{orig_h}px β Enhanced: {new_w}Γ{new_h}px ({scale}Γ upscale)" |
| return result, info |
|
|
| |
| css = """ |
| @import url('https://fonts.googleapis.com/css2?family=Syne:wght@400;600;800&family=DM+Mono:wght@300;400;500&display=swap'); |
| |
| :root { |
| --cream: #f5f0e8; |
| --ink: #0f0e0c; |
| --accent: #c8502a; |
| --muted: #8a8070; |
| --border: #d8d0c0; |
| --card: #faf7f2; |
| } |
| |
| *, *::before, *::after { box-sizing: border-box; } |
| |
| body, .gradio-container { |
| background-color: var(--cream) !important; |
| font-family: 'DM Mono', monospace !important; |
| color: var(--ink) !important; |
| } |
| |
| .gradio-container { |
| max-width: 1100px !important; |
| margin: 0 auto !important; |
| padding: 0 1.5rem 3rem !important; |
| } |
| |
| /* ββ HEADER ββ */ |
| .site-header { |
| padding: 2rem 0 1.5rem 0; |
| border-bottom: 2px solid var(--ink); |
| margin-bottom: 0; |
| display: flex; |
| align-items: flex-start; |
| justify-content: space-between; |
| gap: 1rem; |
| flex-wrap: wrap; |
| } |
| .header-left h1 { |
| font-family: 'Syne', sans-serif; |
| font-size: 2.8rem; font-weight: 800; |
| color: var(--ink); letter-spacing: -2px; |
| -webkit-text-fill-color: var(--ink); |
| line-height: 1; margin: 0; |
| } |
| .header-left h1 span { |
| color: var(--accent); |
| -webkit-text-fill-color: var(--accent); |
| } |
| .header-left p { |
| font-size: 0.68rem; letter-spacing: 2px; |
| text-transform: uppercase; color: var(--muted); |
| -webkit-text-fill-color: var(--muted); |
| margin: 0.4rem 0 0 0; |
| } |
| .header-right { |
| display: flex; flex-direction: column; |
| align-items: flex-end; gap: 0.4rem; |
| } |
| .header-right img { |
| height: 64px; width: auto; |
| object-fit: contain; |
| filter: drop-shadow(0 1px 2px rgba(0,0,0,0.1)); |
| display: none !important; |
| } |
| .header-right .inst-name { |
| font-size: 0.6rem; letter-spacing: 1px; |
| text-transform: uppercase; color: var(--muted); text-align: right; |
| line-height: 1.5; |
| display: none !important; |
| } |
| .badge-row { display: flex; gap: 0.4rem; margin-top: 0.75rem; flex-wrap: wrap; } |
| .badge { |
| background: var(--ink); color: var(--cream); |
| -webkit-text-fill-color: var(--cream); |
| font-size: 0.6rem; letter-spacing: 2px; |
| text-transform: uppercase; padding: 3px 9px; |
| border-radius: 1px; font-family: 'DM Mono', monospace; |
| } |
| .badge.red { background: var(--accent); } |
| |
| /* ββ TABS ββ */ |
| .tab-nav button { |
| font-family: 'DM Mono', monospace !important; |
| font-size: 0.7rem !important; letter-spacing: 2px !important; |
| text-transform: uppercase !important; color: var(--muted) !important; |
| border: none !important; border-bottom: 2px solid transparent !important; |
| background: transparent !important; |
| padding: 0.9rem 1.2rem !important; border-radius: 0 !important; |
| } |
| .tab-nav button.selected { |
| color: var(--ink) !important; |
| border-bottom: 2px solid var(--accent) !important; |
| } |
| |
| /* ββ PROCESSING INDICATOR ββ */ |
| .processing-banner { |
| display: none; |
| background: var(--ink); |
| color: var(--cream); |
| padding: 0.75rem 1rem; |
| border-radius: 2px; |
| font-size: 0.75rem; |
| letter-spacing: 2px; |
| text-align: center; |
| margin-bottom: 0.75rem; |
| animation: pulse 1.5s ease-in-out infinite; |
| } |
| @keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.5} } |
| |
| /* ββ INPUTS ββ */ |
| textarea, input[type="text"] { |
| background: var(--card) !important; |
| border: 1px solid var(--border) !important; |
| color: var(--ink) !important; |
| font-family: 'DM Mono', monospace !important; |
| font-size: 0.82rem !important; border-radius: 2px !important; |
| } |
| label, label span, .label-wrap span { |
| font-family: 'DM Mono', monospace !important; |
| font-size: 0.66rem !important; letter-spacing: 2px !important; |
| text-transform: uppercase !important; color: var(--muted) !important; |
| } |
| input[type="range"] { accent-color: var(--accent) !important; } |
| |
| /* ββ BUTTONS ββ */ |
| button.primary { |
| background: var(--ink) !important; color: var(--cream) !important; |
| font-family: 'DM Mono', monospace !important; |
| font-size: 0.72rem !important; letter-spacing: 2px !important; |
| text-transform: uppercase !important; border: none !important; |
| border-radius: 2px !important; padding: 0.75rem 1.5rem !important; |
| transition: background 0.2s !important; width: 100% !important; |
| } |
| button.primary:hover { background: var(--accent) !important; } |
| button.secondary { |
| background: transparent !important; color: var(--ink) !important; |
| font-family: 'DM Mono', monospace !important; |
| font-size: 0.72rem !important; letter-spacing: 2px !important; |
| text-transform: uppercase !important; |
| border: 1px solid var(--border) !important; |
| border-radius: 2px !important; width: 100% !important; |
| } |
| button.secondary:hover { border-color: var(--ink) !important; } |
| |
| /* ββ IMAGE PANELS ββ */ |
| .gr-image img { |
| border-radius: 2px !important; |
| border: 1px solid var(--border) !important; |
| width: 100% !important; height: auto !important; |
| } |
| .image-wrap { |
| border: 1px solid var(--border); |
| border-radius: 2px; |
| overflow: hidden; |
| background: #1a1a1a; |
| min-height: 220px; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| position: relative; |
| } |
| .image-placeholder { |
| color: var(--cream); |
| font-size: 0.7rem; |
| letter-spacing: 2px; |
| text-transform: uppercase; |
| text-align: center; |
| padding: 3rem; |
| } |
| .image-placeholder .icon { font-size: 2rem; margin-bottom: 0.75rem; } |
| |
| /* ββ TIPS BOX ββ */ |
| .tips-box { |
| padding: 1rem; border: 1px solid var(--border); |
| border-radius: 2px; margin-top: 0.5rem; |
| background: var(--card) !important; |
| } |
| .tips-title { |
| font-size: 0.64rem; letter-spacing: 2px; |
| text-transform: uppercase; color: var(--muted) !important; margin-bottom: 0.5rem; |
| } |
| .tips-body { font-size: 0.73rem; color: var(--ink) !important; line-height: 2.1; background: var(--card) !important; } |
| .tip-chip { |
| display: inline-block; |
| background: var(--ink); color: var(--cream); |
| font-size: 0.6rem; letter-spacing: 1px; |
| padding: 2px 8px; border-radius: 1px; margin: 2px 4px 2px 0; |
| } |
| |
| /* ββ TEAM ββ */ |
| .team-grid { |
| display: grid; |
| grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); |
| gap: 1rem; margin-top: 1.25rem; |
| } |
| .team-card { |
| background: var(--card); border: 1px solid var(--border); |
| border-radius: 2px; padding: 1.1rem 1.25rem; |
| transition: border-color 0.2s, box-shadow 0.2s; |
| } |
| .team-card:hover { border-color: var(--ink); box-shadow: 4px 4px 0 var(--ink); } |
| .team-card.leader { border-color: var(--accent); background: #fff8f5; } |
| .team-card.leader:hover { box-shadow: 4px 4px 0 var(--accent); } |
| .card-role { font-size: 0.6rem; letter-spacing: 3px; text-transform: uppercase; color: var(--muted) !important; margin-bottom: 0.3rem; } |
| .card-name { font-family: 'Syne', sans-serif; font-size: 1.05rem; font-weight: 700; color: var(--ink) !important; margin-bottom: 0.15rem; } |
| .card-roll { font-size: 0.68rem; color: var(--muted) !important; margin-bottom: 0.6rem; } |
| .card-desc { font-size: 0.72rem; color: var(--ink) !important; line-height: 1.7; border-top: 1px solid var(--border); padding-top: 0.6rem; } |
| |
| .course-strip { |
| background: var(--ink); color: var(--cream); |
| padding: 1rem 1.5rem; border-radius: 2px; |
| display: flex; justify-content: space-between; |
| align-items: center; flex-wrap: wrap; gap: 0.5rem; |
| margin-bottom: 1.25rem; |
| } |
| .course-strip span { font-size: 0.64rem; letter-spacing: 2px; text-transform: uppercase; opacity: 0.6; color: var(--cream) !important; } |
| .course-strip strong { font-family: 'Syne', sans-serif; font-size: 0.92rem; font-weight: 700; display: block; margin-top: 2px; color: var(--cream) !important; } |
| |
| /* ββ MODEL TAB ββ */ |
| .model-hero { |
| background: var(--card); |
| color: var(--ink); |
| border: 1px solid var(--border); |
| padding: 2rem 1.75rem; border-radius: 2px; |
| margin-bottom: 1.25rem; position: relative; overflow: hidden; |
| } |
| .model-hero::before { |
| content: 'GAN'; position: absolute; right: -10px; top: 50%; |
| transform: translateY(-50%); |
| font-family: 'Syne', sans-serif; font-size: 7rem; font-weight: 800; |
| color: rgba(15,14,12,0.05); pointer-events: none; |
| } |
| .model-hero h2 { font-family: 'Syne', sans-serif; font-size: 1.9rem; font-weight: 800; margin: 0 0 0.5rem 0; color: var(--ink); } |
| .model-hero h2 span { color: #e8a87c; } |
| .model-hero p { font-size: 0.8rem; line-height: 1.8; color: var(--muted); max-width: 600px; margin: 0; } |
| |
| .stat-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; margin-bottom: 1.25rem; } |
| .stat-card { background: var(--card); border: 1px solid var(--border); border-radius: 2px; padding: 1rem; text-align: center; } |
| .stat-val { font-family: 'Syne', sans-serif; font-size: 1.8rem; font-weight: 800; color: var(--accent); line-height: 1; } |
| .stat-lbl { font-size: 0.62rem; letter-spacing: 2px; text-transform: uppercase; color: var(--muted); margin-top: 0.3rem; } |
| |
| .section-title { |
| font-size: 0.66rem; letter-spacing: 3px; text-transform: uppercase; |
| color: var(--muted); margin: 1.5rem 0 1rem 0; |
| padding-bottom: 0.5rem; border-bottom: 1px solid var(--border); |
| } |
| .explainer-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1rem; } |
| .explainer-card { background: var(--card); border: 1px solid var(--border); border-radius: 2px; padding: 1.25rem; } |
| .explainer-icon { font-size: 1.4rem; margin-bottom: 0.5rem; } |
| .explainer-title { font-family: 'Syne', sans-serif; font-size: 0.95rem; font-weight: 700; color: var(--ink) !important; margin-bottom: 0.4rem; } |
| .explainer-desc { font-size: 0.73rem; color: var(--muted) !important; line-height: 1.75; } |
| .dark-note { |
| background: var(--card); |
| color: var(--muted); |
| border: 1px solid var(--border); |
| padding: 1.25rem 1.5rem; border-radius: 2px; |
| font-size: 0.75rem; line-height: 1.8; margin-top: 1rem; |
| } |
| .dark-note strong { color: var(--ink) !important; font-family: 'Syne', sans-serif; } |
| .dark-note em { |
| color: var(--ink) !important; |
| -webkit-text-fill-color: var(--ink) !important; |
| opacity: 1 !important; |
| background: transparent !important; |
| } |
| |
| /* render stability: avoid washed-out text during browser repaint/translation */ |
| .team-card, |
| .team-card *, |
| .explainer-card, |
| .explainer-card *, |
| .dark-note, |
| .dark-note * { |
| text-shadow: none !important; |
| } |
| |
| /* ββ HF SPACES AGGRESSIVE TEXT COLOR FIX ββ */ |
| /* HF Spaces forces light text (#fff or #fafafa), which disappears on light backgrounds */ |
| /* This section uses maximum specificity and !important to force dark text everywhere */ |
| |
| body, html, .gradio-container { |
| color: var(--ink) !important; |
| } |
| |
| /* Team cards: explicitly force all text dark */ |
| .team-card { |
| color: var(--ink) !important; |
| } |
| .team-card h3, |
| .team-card h4, |
| .team-card p, |
| .team-card span, |
| .team-card div { |
| color: var(--ink) !important; |
| } |
| |
| .card-name, .card-role, .card-roll, .card-desc { |
| color: var(--ink) !important; |
| } |
| |
| /* Model/explainer cards */ |
| .explainer-card, |
| .explainer-card h3, |
| .explainer-card h4, |
| .explainer-card p, |
| .explainer-card div, |
| .explainer-card span { |
| color: var(--ink) !important; |
| } |
| |
| .explainer-title { |
| color: var(--ink) !important; |
| } |
| |
| /* Header section: force ink color on everything */ |
| .site-header { |
| color: var(--ink) !important; |
| } |
| |
| .header-left h1, |
| .header-left p { |
| color: var(--ink) !important; |
| -webkit-text-fill-color: var(--ink) !important; |
| opacity: 1 !important; |
| } |
| |
| .header-left h1 span { |
| color: var(--accent) !important; |
| -webkit-text-fill-color: var(--accent) !important; |
| } |
| |
| .header-left p { |
| color: var(--muted) !important; |
| -webkit-text-fill-color: var(--muted) !important; |
| } |
| |
| .badge, |
| .badge * { |
| color: var(--cream) !important; |
| -webkit-text-fill-color: var(--cream) !important; |
| opacity: 1 !important; |
| } |
| |
| .badge.red, |
| .badge.red * { |
| color: #fff7ef !important; |
| -webkit-text-fill-color: #fff7ef !important; |
| } |
| |
| /* Keep key warning/info banners dark and readable */ |
| .dark-banner, |
| .dark-banner * { |
| background: var(--ink) !important; |
| color: var(--cream) !important; |
| border-color: #2b2a27 !important; |
| } |
| |
| .dark-banner strong { |
| color: #e8a87c !important; |
| } |
| |
| .dark-chip { |
| display: inline-block; |
| background: #1a1a1a !important; |
| color: var(--cream) !important; |
| border: 1px solid #343331 !important; |
| padding: 2px 6px; |
| border-radius: 1px; |
| margin: 0 3px; |
| font-size: 0.68rem; |
| } |
| |
| /* Course strip: this should stay cream on dark background */ |
| .course-strip, |
| .course-strip span, |
| .course-strip strong { |
| color: var(--cream) !important; |
| } |
| |
| /* Dark note section: force ink for strong, muted for normal */ |
| .dark-note { |
| color: var(--muted) !important; |
| } |
| .dark-note strong, |
| .dark-note h3, |
| .dark-note h4 { |
| color: var(--ink) !important; |
| } |
| |
| /* Stat cards and model hero */ |
| .stat-card, |
| .stat-card *, |
| .model-hero, |
| .model-hero * { |
| color: var(--ink) !important; |
| } |
| |
| .stat-val { |
| color: var(--accent) !important; |
| } |
| |
| .model-hero h2 { |
| color: var(--ink) !important; |
| } |
| |
| .model-hero h2 span { |
| color: #e8a87c !important; |
| } |
| |
| /* ββ GRADIO FORM ELEMENTS: FORCE DARK TEXT ββ */ |
| /* HF Spaces applies light blue (#4a9eff or similar) to all Gradio form components */ |
| /* This section targets ALL form elements on the Enhance tab */ |
| |
| .label-wrap, |
| .label-wrap *, |
| .label-wrap span, |
| .label-wrap label { |
| color: var(--ink) !important; |
| background: var(--card) !important; |
| } |
| |
| .gr-image, |
| .gr-image *, |
| .gr-image label, |
| .gr-image span, |
| .gr-image > div, |
| .gr-image > div > div, |
| .gr-image [data-testid="image"], |
| .gr-image [data-testid="image"] * { |
| color: var(--ink) !important; |
| background: var(--card) !important; |
| } |
| |
| .gr-textbox, |
| .gr-textbox *, |
| .gr-textbox label { |
| color: var(--ink) !important; |
| background: var(--card) !important; |
| } |
| |
| .gr-button, |
| .gr-button *, |
| .gr-button label { |
| color: var(--ink) !important; |
| } |
| |
| /* Tips and instructions boxes */ |
| .tips-title, |
| .tips-body, |
| .tips-box, |
| .tips-box * { |
| color: var(--ink) !important; |
| background: var(--card) !important; |
| } |
| |
| .tip-chip { |
| background: var(--ink) !important; |
| color: var(--cream) !important; |
| } |
| |
| /* Processing indicator and info text */ |
| .processing-banner, |
| .processing-banner *, |
| .info-text, |
| .info-text * { |
| color: var(--ink) !important; |
| } |
| |
| /* Form wrapper containers: ensure light backgrounds */ |
| .gradio-container > div, |
| .gradio-container .form-box, |
| .gradio-container form { |
| background: var(--card) !important; |
| } |
| |
| /* ββ SCOPED HF COLOR FIXES (avoid black-on-black) ββ */ |
| .gradio-container, |
| .gradio-container label, |
| .gradio-container input, |
| .gradio-container textarea { |
| color: var(--ink) !important; |
| } |
| |
| /* Keep form controls readable without overriding themed dark content blocks */ |
| .gr-textbox, |
| .gr-number, |
| .gradio-container input[type="text"], |
| .gradio-container input[type="number"], |
| .gradio-container textarea { |
| background: var(--card) !important; |
| border: 1px solid var(--border) !important; |
| color: var(--ink) !important; |
| } |
| |
| input::placeholder, |
| textarea::placeholder { |
| color: var(--muted) !important; |
| } |
| |
| footer { display: none !important; } |
| ::-webkit-scrollbar { width: 4px; } |
| ::-webkit-scrollbar-track { background: var(--cream); } |
| ::-webkit-scrollbar-thumb { background: var(--muted); border-radius: 2px; } |
| """ |
|
|
| |
| esrgan_diagram = """ |
| <svg viewBox="0 0 900 200" xmlns="http://www.w3.org/2000/svg" style="width:100%;border-radius:2px;margin-bottom:1rem;"> |
| <rect width="900" height="200" fill="#0f0e0c"/> |
| <rect x="20" y="60" width="100" height="80" rx="2" fill="#1a1a1a" stroke="#3a3a3a" stroke-width="1"/> |
| <text x="70" y="94" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="9">LOW-RES</text> |
| <text x="70" y="108" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="8">Input Image</text> |
| <rect x="35" y="120" width="70" height="12" rx="1" fill="#2a2a2a"/> |
| <text x="70" y="130" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">e.g. 64Γ64 px</text> |
| <line x1="120" y1="100" x2="155" y2="100" stroke="#3a3a3a" stroke-width="1.5" marker-end="url(#arr)"/> |
| <rect x="155" y="70" width="80" height="60" rx="2" fill="#1a1a1a" stroke="#3a3a3a" stroke-width="1"/> |
| <text x="195" y="97" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="8">TILE</text> |
| <text x="195" y="110" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="8">SPLIT</text> |
| <rect x="165" y="116" width="60" height="10" rx="1" fill="#2a2a2a"/> |
| <text x="195" y="124" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">256Γ256 tiles</text> |
| <line x1="235" y1="100" x2="270" y2="100" stroke="#3a3a3a" stroke-width="1.5" marker-end="url(#arr)"/> |
| <rect x="270" y="40" width="260" height="120" rx="2" fill="#1a1208" stroke="#c8502a" stroke-width="1.5"/> |
| <text x="400" y="60" text-anchor="middle" fill="#e8a87c" font-family="monospace" font-size="9" font-weight="bold">GENERATOR (RRDB Network)</text> |
| <rect x="285" y="70" width="55" height="40" rx="2" fill="#c8502a" opacity="0.85"/> |
| <text x="312" y="88" text-anchor="middle" fill="#fff" font-family="monospace" font-size="7">RRDB</text> |
| <text x="312" y="100" text-anchor="middle" fill="#fff" font-family="monospace" font-size="7">Block 1</text> |
| <line x1="340" y1="90" x2="355" y2="90" stroke="#c8502a" stroke-width="1" marker-end="url(#arr2)"/> |
| <rect x="355" y="70" width="55" height="40" rx="2" fill="#c8502a" opacity="0.85"/> |
| <text x="382" y="88" text-anchor="middle" fill="#fff" font-family="monospace" font-size="7">RRDB</text> |
| <text x="382" y="100" text-anchor="middle" fill="#fff" font-family="monospace" font-size="7">Block 2</text> |
| <text x="430" y="93" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="10">Β·Β·Β·</text> |
| <rect x="445" y="70" width="55" height="40" rx="2" fill="#c8502a" opacity="0.85"/> |
| <text x="472" y="88" text-anchor="middle" fill="#fff" font-family="monospace" font-size="7">RRDB</text> |
| <text x="472" y="100" text-anchor="middle" fill="#fff" font-family="monospace" font-size="7">Block 6</text> |
| <text x="400" y="145" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">Dense skip connections Β· learns textures, edges & fine detail</text> |
| <line x1="530" y1="100" x2="560" y2="100" stroke="#3a3a3a" stroke-width="1.5" marker-end="url(#arr)"/> |
| <rect x="560" y="70" width="80" height="60" rx="2" fill="#1a1a1a" stroke="#3a3a3a" stroke-width="1"/> |
| <text x="600" y="94" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="8">PIXEL</text> |
| <text x="600" y="107" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="8">SHUFFLE</text> |
| <rect x="570" y="116" width="60" height="10" rx="1" fill="#2a2a2a"/> |
| <text x="600" y="124" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">Γ4 upscale</text> |
| <line x1="640" y1="100" x2="670" y2="100" stroke="#3a3a3a" stroke-width="1.5" marker-end="url(#arr)"/> |
| <rect x="670" y="70" width="80" height="60" rx="2" fill="#1a1a1a" stroke="#3a3a3a" stroke-width="1"/> |
| <text x="710" y="94" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="8">TILE</text> |
| <text x="710" y="107" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="8">MERGE</text> |
| <rect x="680" y="116" width="60" height="10" rx="1" fill="#2a2a2a"/> |
| <text x="710" y="124" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">stitch tiles</text> |
| <line x1="750" y1="100" x2="775" y2="100" stroke="#3a3a3a" stroke-width="1.5" marker-end="url(#arr)"/> |
| <rect x="775" y="60" width="105" height="80" rx="2" fill="#1a2a1a" stroke="#00cc7a" stroke-width="1.5"/> |
| <text x="827" y="90" text-anchor="middle" fill="#00ff9d" font-family="monospace" font-size="9">HIGH-RES</text> |
| <text x="827" y="103" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="8">Output Image</text> |
| <rect x="790" y="114" width="75" height="12" rx="1" fill="#1a3a1a"/> |
| <text x="827" y="123" text-anchor="middle" fill="#00cc7a" font-family="monospace" font-size="7">256Γ256 px</text> |
| <defs> |
| <marker id="arr" markerWidth="6" markerHeight="6" refX="6" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 Z" fill="#3a3a3a"/></marker> |
| <marker id="arr2" markerWidth="6" markerHeight="6" refX="6" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 Z" fill="#c8502a"/></marker> |
| </defs> |
| </svg> |
| """ |
|
|
| |
| gan_diagram = """ |
| <svg viewBox="0 0 860 180" xmlns="http://www.w3.org/2000/svg" style="width:100%;border-radius:2px;margin:0.75rem 0 1rem 0;"> |
| <rect width="860" height="180" fill="#0f0e0c"/> |
| <rect x="20" y="55" width="110" height="70" rx="2" fill="#1a1a1a" stroke="#3a3a3a" stroke-width="1"/> |
| <text x="75" y="84" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="8">LOW-RES</text> |
| <text x="75" y="97" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="8">IMAGE</text> |
| <text x="75" y="113" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">degraded input</text> |
| <line x1="130" y1="90" x2="165" y2="90" stroke="#3a3a3a" stroke-width="1.5" marker-end="url(#b1)"/> |
| <rect x="165" y="40" width="130" height="100" rx="2" fill="#1a1208" stroke="#c8502a" stroke-width="1.5"/> |
| <text x="230" y="65" text-anchor="middle" fill="#e8a87c" font-family="monospace" font-size="9" font-weight="bold">GENERATOR</text> |
| <text x="230" y="82" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">RRDB Network</text> |
| <text x="230" y="98" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">Creates fake HR image</text> |
| <text x="230" y="114" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">Tries to fool detector</text> |
| <text x="230" y="128" text-anchor="middle" fill="#c8502a" font-family="monospace" font-size="7">β improved via feedback</text> |
| <line x1="295" y1="90" x2="330" y2="90" stroke="#c8502a" stroke-width="1.5" marker-end="url(#b2)"/> |
| <rect x="330" y="50" width="100" height="55" rx="2" fill="#1a1a1a" stroke="#c8502a" stroke-width="1"/> |
| <text x="380" y="74" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="8">FAKE HR</text> |
| <text x="380" y="88" text-anchor="middle" fill="#c8502a" font-family="monospace" font-size="7">generated output</text> |
| <rect x="330" y="125" width="100" height="40" rx="2" fill="#1a2a1a" stroke="#00cc7a" stroke-width="1"/> |
| <text x="380" y="143" text-anchor="middle" fill="#00ff9d" font-family="monospace" font-size="8">REAL HR</text> |
| <text x="380" y="157" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">ground truth</text> |
| <line x1="430" y1="77" x2="490" y2="108" stroke="#c8502a" stroke-width="1.2" marker-end="url(#b3)"/> |
| <line x1="430" y1="145" x2="490" y2="125" stroke="#00cc7a" stroke-width="1.2" marker-end="url(#b4)"/> |
| <rect x="490" y="45" width="130" height="100" rx="2" fill="#0a1a1a" stroke="#00cc7a" stroke-width="1.5"/> |
| <text x="555" y="68" text-anchor="middle" fill="#00ff9d" font-family="monospace" font-size="9" font-weight="bold">DISCRIMINATOR</text> |
| <text x="555" y="85" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">Is this real or fake?</text> |
| <text x="555" y="101" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">Scores both images</text> |
| <text x="555" y="117" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">Sends loss signal</text> |
| <text x="555" y="133" text-anchor="middle" fill="#00cc7a" font-family="monospace" font-size="7">β trains generator</text> |
| <line x1="620" y1="95" x2="655" y2="95" stroke="#00cc7a" stroke-width="1.5" marker-end="url(#b4)"/> |
| <rect x="655" y="60" width="110" height="70" rx="2" fill="#1a1a1a" stroke="#3a3a3a" stroke-width="1"/> |
| <text x="710" y="85" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="8">LOSS SCORE</text> |
| <text x="710" y="100" text-anchor="middle" fill="#c8502a" font-family="monospace" font-size="7">Real / Fake verdict</text> |
| <text x="710" y="116" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">Updates both networks</text> |
| <path d="M 710 130 Q 710 165 400 165 Q 230 165 230 140" stroke="#444" stroke-width="1" fill="none" stroke-dasharray="4,3" marker-end="url(#b5)"/> |
| <text x="460" y="175" text-anchor="middle" fill="#444" font-family="monospace" font-size="7">training feedback loop β repeated millions of times</text> |
| <defs> |
| <marker id="b1" markerWidth="6" markerHeight="6" refX="6" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 Z" fill="#3a3a3a"/></marker> |
| <marker id="b2" markerWidth="6" markerHeight="6" refX="6" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 Z" fill="#c8502a"/></marker> |
| <marker id="b3" markerWidth="6" markerHeight="6" refX="6" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 Z" fill="#c8502a"/></marker> |
| <marker id="b4" markerWidth="6" markerHeight="6" refX="6" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 Z" fill="#00cc7a"/></marker> |
| <marker id="b5" markerWidth="6" markerHeight="6" refX="6" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 Z" fill="#444"/></marker> |
| </defs> |
| </svg> |
| """ |
|
|
| |
| loss_diagram = """ |
| <svg viewBox="0 0 860 160" xmlns="http://www.w3.org/2000/svg" style="width:100%;border-radius:2px;margin:0.75rem 0 1rem 0;"> |
| <rect width="860" height="160" fill="#0f0e0c"/> |
| <!-- L_total --> |
| <rect x="20" y="50" width="120" height="60" rx="2" fill="#1a1208" stroke="#c8502a" stroke-width="1.5"/> |
| <text x="80" y="75" text-anchor="middle" fill="#e8a87c" font-family="monospace" font-size="9" font-weight="bold">Total Loss</text> |
| <text x="80" y="92" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">L = Lp + Ξ»Ladv + Ξ·Lperc</text> |
| <line x1="140" y1="80" x2="180" y2="55" stroke="#555" stroke-width="1" stroke-dasharray="3,2"/> |
| <line x1="140" y1="80" x2="180" y2="80" stroke="#555" stroke-width="1" stroke-dasharray="3,2"/> |
| <line x1="140" y1="80" x2="180" y2="108" stroke="#555" stroke-width="1" stroke-dasharray="3,2"/> |
| <!-- Pixel Loss --> |
| <rect x="180" y="30" width="150" height="50" rx="2" fill="#1a1a1a" stroke="#3a3a3a" stroke-width="1"/> |
| <text x="255" y="52" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="8">Pixel Loss (L1 / MSE)</text> |
| <text x="255" y="67" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">pixel-by-pixel difference</text> |
| <!-- Adversarial Loss --> |
| <rect x="180" y="62" width="150" height="50" rx="2" fill="#1a1a1a" stroke="#c8502a" stroke-width="1"/> |
| <text x="255" y="83" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="8">Adversarial Loss</text> |
| <text x="255" y="98" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">fool the discriminator</text> |
| <!-- Perceptual Loss --> |
| <rect x="180" y="95" width="150" height="50" rx="2" fill="#1a2a1a" stroke="#00cc7a" stroke-width="1"/> |
| <text x="255" y="116" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="8">Perceptual Loss (VGG)</text> |
| <text x="255" y="131" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">feature-level similarity</text> |
| <!-- Arrows to effect --> |
| <line x1="330" y1="55" x2="370" y2="55" stroke="#3a3a3a" stroke-width="1" marker-end="url(#c1)"/> |
| <line x1="330" y1="87" x2="370" y2="87" stroke="#c8502a" stroke-width="1" marker-end="url(#c2)"/> |
| <line x1="330" y1="120" x2="370" y2="120" stroke="#00cc7a" stroke-width="1" marker-end="url(#c3)"/> |
| <!-- Effect boxes --> |
| <rect x="370" y="30" width="200" height="50" rx="2" fill="#111" stroke="#2a2a2a" stroke-width="1"/> |
| <text x="470" y="52" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="7">Ensures structural fidelity</text> |
| <text x="470" y="66" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">Prevents totally wrong outputs</text> |
| <rect x="370" y="62" width="200" height="50" rx="2" fill="#111" stroke="#2a2a2a" stroke-width="1"/> |
| <text x="470" y="83" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="7">Produces sharp, realistic textures</text> |
| <text x="470" y="97" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">Prevents blurry outputs</text> |
| <rect x="370" y="95" width="200" height="50" rx="2" fill="#111" stroke="#2a2a2a" stroke-width="1"/> |
| <text x="470" y="116" text-anchor="middle" fill="#f5f0e8" font-family="monospace" font-size="7">Matches high-level features</text> |
| <text x="470" y="130" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">Preserves semantic content</text> |
| <!-- Combined result --> |
| <line x1="570" y1="87" x2="610" y2="87" stroke="#555" stroke-width="1" marker-end="url(#c4)"/> |
| <rect x="610" y="55" width="230" height="65" rx="2" fill="#1a1208" stroke="#c8502a" stroke-width="1.5"/> |
| <text x="725" y="78" text-anchor="middle" fill="#e8a87c" font-family="monospace" font-size="8" font-weight="bold">Result: Perceptually Sharp</text> |
| <text x="725" y="94" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">Structurally correct + photorealistic</text> |
| <text x="725" y="108" text-anchor="middle" fill="#8a8070" font-family="monospace" font-size="7">texture + semantically meaningful</text> |
| <defs> |
| <marker id="c1" markerWidth="6" markerHeight="6" refX="6" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 Z" fill="#3a3a3a"/></marker> |
| <marker id="c2" markerWidth="6" markerHeight="6" refX="6" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 Z" fill="#c8502a"/></marker> |
| <marker id="c3" markerWidth="6" markerHeight="6" refX="6" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 Z" fill="#00cc7a"/></marker> |
| <marker id="c4" markerWidth="6" markerHeight="6" refX="6" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 Z" fill="#555"/></marker> |
| </defs> |
| </svg> |
| """ |
|
|
| |
| with gr.Blocks(title="ArtUpscale β AI Super Resolution") as demo: |
|
|
| gr.HTML(""" |
| <div class="site-header notranslate" translate="no"> |
| <div class="header-left"> |
| <h1 class="notranslate" translate="no">Art<span>Upscale</span></h1> |
| <p class="notranslate" translate="no">AI-Powered Super Resolution Β· CS360 Artificial Intelligence Β· Semester 4</p> |
| <div class="badge-row notranslate" translate="no"> |
| <div class="badge red">Real-ESRGAN</div> |
| <div class="badge">4Γ Upscale</div> |
| <div class="badge">Artwork Optimized</div> |
| <div class="badge">Deep Learning</div> |
| <div class="badge">CS360</div> |
| </div> |
| </div> |
| <div class="header-right"> |
| <img src="https://www.rgipt.ac.in/images/logo.png" |
| alt="RGIPT Logo" |
| onerror="this.style.display='none'"/> |
| <div class="inst-name">Rajiv Gandhi Institute<br>of Petroleum Technology<br>Jais, Amethi</div> |
| </div> |
| </div> |
| """) |
|
|
| with gr.Tabs(elem_classes=["tab-nav"]): |
|
|
| |
| with gr.Tab("β¦ Enhance"): |
|
|
| gr.HTML(""" |
| <div class="dark-banner" style="padding:0.75rem 1rem; |
| border-radius:2px;font-size:0.72rem;letter-spacing:1px; |
| margin:1rem 0 0.75rem 0;line-height:1.7;"> |
| <strong>β‘ For fast demo results</strong> β use small artwork images (under 300Γ300px). |
| Try anime thumbnails, pixel art, game sprites, or low-res manga panels. |
| Processing time on CPU: <strong>~8β15s for small images, ~30β60s for large ones.</strong> |
| <br>Good test sources: |
| <span class="dark-chip">Google Images β Tools β Size β Small</span> |
| <span class="dark-chip">Pinterest low-res art</span> |
| <span class="dark-chip">Game sprite sheets</span> |
| </div> |
| """) |
|
|
| with gr.Row(equal_height=False): |
| with gr.Column(scale=1, min_width=320): |
| input_image = gr.Image( |
| type="pil", label="Upload Artwork", |
| elem_classes=["gr-image"], |
| height=280 |
| ) |
| scale = gr.Slider( |
| minimum=4, maximum=4, value=4, step=1, |
| label="Upscale Factor", |
| visible=False |
| ) |
| enhance_btn = gr.Button("β¦ Enhance Image", variant="primary") |
| clear_btn = gr.Button("β« Clear", variant="secondary") |
|
|
| gr.HTML(""" |
| <div class="tips-box" style="margin-top:0.75rem;background:#faf7f2;border:1px solid #d8d0c0;color:#0f0e0c;"> |
| <div class="tips-title">Tips for best results</div> |
| <div class="tips-body"> |
| Β· Anime, manga & illustrations β best output<br> |
| Β· Pixel art β use 4Γ for crisp upscale<br> |
| Β· Photos work too but are slower<br> |
| Β· Start with 4Γ β it is the supported upscale<br> |
| Β· The queue timer is normal β it's processing! |
| </div> |
| <div style="margin-top:0.75rem;"> |
| <div class="tips-title">Good test images</div> |
| <span class="tip-chip">anime thumbnail</span> |
| <span class="tip-chip">pixel art sprite</span> |
| <span class="tip-chip">manga panel</span> |
| <span class="tip-chip">game screenshot</span> |
| <span class="tip-chip">low-res painting</span> |
| </div> |
| </div> |
| """) |
|
|
| with gr.Column(scale=1, min_width=320): |
| gr.HTML(""" |
| <div id="processing-hint" class="dark-banner" style=" |
| border:1px solid #c8502a;padding:0.6rem 1rem;border-radius:2px; |
| font-size:0.7rem;letter-spacing:1px;margin-bottom:0.5rem; |
| text-align:center;"> |
| β³ Processing takes 10β60s on CPU Β· The queue timer below the image is normal Β· Please wait |
| </div> |
| """) |
| output_image = gr.Image( |
| type="pil", label="Enhanced Output", |
| elem_classes=["gr-image"], |
| height=280 |
| ) |
| info_box = gr.Textbox( |
| label="Resolution Info", |
| interactive=False, |
| placeholder="Enhancement details will appear here..." |
| ) |
| gr.HTML(""" |
| <div style="padding:1rem;background:#faf7f2;border:1px solid #d8d0c0;border-radius:2px;margin-top:0.5rem;"> |
| <div style="font-size:0.64rem;letter-spacing:2px;text-transform:uppercase;color:#8a8070;margin-bottom:0.5rem;">What just happened?</div> |
| <div style="font-size:0.72rem;color:#0f0e0c;line-height:1.9;"> |
| The model analysed every 256Γ256 tile of your image, |
| ran it through 6 RRDB neural network blocks, |
| and reconstructed fine detail at up to 4Γ the original resolution β |
| synthesizing sharp edges and textures that weren't in the original. |
| </div> |
| </div> |
| """) |
|
|
| enhance_btn.click(fn=enhance, inputs=[input_image, scale], outputs=[output_image, info_box]) |
| clear_btn.click(fn=lambda: (None, None, ""), outputs=[input_image, output_image, info_box]) |
|
|
| |
| with gr.Tab("β The Model"): |
| gr.HTML(f""" |
| <div style="margin-top:1.5rem;"> |
| |
| <div class="model-hero"> |
| <h2>Real-<span>ESRGAN</span></h2> |
| <p> |
| Real-Enhanced Super-Resolution Generative Adversarial Network β |
| a deep learning model that doesn't just stretch pixels, |
| it <em>invents</em> the fine detail that was lost in compression or downsizing. |
| Think of it as an AI that has studied millions of high-resolution images |
| and learned exactly what sharp edges and crisp textures look like β |
| then applies that knowledge to reconstruct your blurry image from scratch. |
| </p> |
| </div> |
| |
| <div class="stat-row"> |
| <div class="stat-card"><div class="stat-val">4Γ</div><div class="stat-lbl">Max Upscale</div></div> |
| <div class="stat-card"><div class="stat-val">6B</div><div class="stat-lbl">RRDB Blocks</div></div> |
| <div class="stat-card"><div class="stat-val">17M</div><div class="stat-lbl">Parameters</div></div> |
| <div class="stat-card"><div class="stat-val">3</div><div class="stat-lbl">Loss Functions</div></div> |
| </div> |
| |
| <div class="section-title">What is a GAN? β The Forger & The Detective</div> |
| {gan_diagram} |
| <div class="explainer-grid"> |
| <div class="explainer-card"> |
| <div class="explainer-icon">π¨</div> |
| <div class="explainer-title">Generator β The Art Forger</div> |
| <div class="explainer-desc"> |
| Takes a blurry, low-res input and tries to produce a crisp, |
| photorealistic high-res version. It starts terrible and gets better |
| every time the discriminator catches it out. Its job is to make fakes |
| so good that even an expert can't tell them apart from the real thing. |
| </div> |
| </div> |
| <div class="explainer-card"> |
| <div class="explainer-icon">π</div> |
| <div class="explainer-title">Discriminator β The Detective</div> |
| <div class="explainer-desc"> |
| A second network trained purely to spot fakes. It sees both real |
| high-res images and the generator's outputs, and tries to label each one. |
| Its feedback is what drives the generator to keep improving β without it, |
| the generator would just produce blurry averages. |
| </div> |
| </div> |
| <div class="explainer-card"> |
| <div class="explainer-icon">π</div> |
| <div class="explainer-title">Adversarial Training Loop</div> |
| <div class="explainer-desc"> |
| The two networks compete millions of times. The forger gets better at |
| fooling, the detective gets better at catching. After enough rounds, |
| the generator has learned to produce images so convincing the |
| discriminator genuinely can't tell what's real. |
| </div> |
| </div> |
| <div class="explainer-card"> |
| <div class="explainer-icon">β¨</div> |
| <div class="explainer-title">Why Not Just Bicubic?</div> |
| <div class="explainer-desc"> |
| Bicubic interpolation averages nearby pixels β it makes mathematical sense |
| but looks blurry. GANs instead ask "what would a real high-res image look like |
| here?" and synthesise convincing detail. The difference is |
| <em>interpolation</em> vs <em>learned perception</em>. |
| </div> |
| </div> |
| </div> |
| |
| <div class="section-title">ESRGAN Architecture & Pipeline</div> |
| {esrgan_diagram} |
| <div class="explainer-grid"> |
| <div class="explainer-card"> |
| <div class="explainer-icon">π§±</div> |
| <div class="explainer-title">RRDB β Residual-in-Residual Dense Blocks</div> |
| <div class="explainer-desc"> |
| The core building unit. Each RRDB contains dense connections where every layer |
| receives input from all previous layers β letting gradients flow freely |
| during training and allowing the network to learn extremely fine texture patterns. |
| Stacking 6 of these creates a deep feature extractor without gradient degradation. |
| </div> |
| </div> |
| <div class="explainer-card"> |
| <div class="explainer-icon">π²</div> |
| <div class="explainer-title">Tile-Based Inference</div> |
| <div class="explainer-desc"> |
| Images are split into overlapping 256Γ256 tiles processed individually, |
| then stitched back. The overlap (tile padding) prevents visible seams. |
| This lets the model run on consumer hardware β no GPU needed β |
| and makes RAM usage predictable regardless of image size. |
| </div> |
| </div> |
| <div class="explainer-card"> |
| <div class="explainer-icon">π</div> |
| <div class="explainer-title">Pixel Shuffle Upscaling</div> |
| <div class="explainer-desc"> |
| Rather than resizing first (causing blur), the network works at the original |
| resolution throughout. At the very end, a pixel-shuffle layer rearranges |
| learned sub-pixel channels into the final upscaled output β |
| preserving all the sharpness built up through the RRDB blocks. |
| </div> |
| </div> |
| <div class="explainer-card"> |
| <div class="explainer-icon">π</div> |
| <div class="explainer-title">Anime 6B Variant</div> |
| <div class="explainer-desc"> |
| Fine-tuned on anime and illustrated art using only 6 RRDB blocks |
| (vs 23 in the full model) for faster CPU inference. |
| It's optimised for clean linework, flat colour shading, |
| and the vibrant palette of illustrated content β exactly what we use here. |
| </div> |
| </div> |
| </div> |
| |
| <div class="section-title">Loss Functions β How the Model Learns</div> |
| {loss_diagram} |
| <div class="explainer-grid"> |
| <div class="explainer-card"> |
| <div class="explainer-icon">π</div> |
| <div class="explainer-title">Pixel Loss (L1 / MSE)</div> |
| <div class="explainer-desc"> |
| Compares the output image to the real high-res image pixel by pixel. |
| Simple but essential β it ensures the overall structure and colour |
| are correct. On its own it produces blurry results because it |
| averages all possible sharp outputs into one smooth prediction. |
| </div> |
| </div> |
| <div class="explainer-card"> |
| <div class="explainer-icon">βοΈ</div> |
| <div class="explainer-title">Adversarial Loss</div> |
| <div class="explainer-desc"> |
| Measures how well the generator fools the discriminator. |
| This is the engine of sharpness β it pushes the generator to produce |
| outputs that look statistically indistinguishable from real high-res images, |
| forcing it to synthesise convincing textures and edges. |
| </div> |
| </div> |
| <div class="explainer-card"> |
| <div class="explainer-icon">π§ </div> |
| <div class="explainer-title">Perceptual Loss (VGG Features)</div> |
| <div class="explainer-desc"> |
| Uses a pre-trained VGG network to compare images at a feature level |
| rather than pixel level. Instead of asking "are these pixels identical?", |
| it asks "do these images contain the same objects and structures?" |
| This preserves semantic meaning even when pixel values differ. |
| </div> |
| </div> |
| <div class="explainer-card"> |
| <div class="explainer-icon">βοΈ</div> |
| <div class="explainer-title">Combined Loss = Best of All Three</div> |
| <div class="explainer-desc"> |
| The final loss is a weighted sum: pixel loss keeps structure correct, |
| adversarial loss adds sharpness and realism, perceptual loss preserves |
| semantic content. Together they prevent the three failure modes: |
| structural wrong output, blurriness, and semantic distortion. |
| </div> |
| </div> |
| </div> |
| |
| <div class="dark-note"> |
| <strong>The Key Insight</strong><br> |
| Traditional methods ask <em>"what pixel value makes mathematical sense here?"</em> |
| Real-ESRGAN asks <em>"what would a human photographer actually have captured here?"</em> |
| That shift β from interpolation to learned perception β is why the output looks |
| sharp and natural rather than smooth and artificial. |
| The three-loss training framework ensures the model is simultaneously accurate, |
| sharp, and semantically meaningful. |
| </div> |
| </div> |
| """) |
|
|
| |
| with gr.Tab("β Our Team"): |
| gr.HTML(""" |
| <div style="margin-top:1.5rem;"> |
| <div class="course-strip"> |
| <div><span>Course</span><strong>CS360 Β· Artificial Intelligence</strong></div> |
| <div><span>Semester</span><strong>4th Semester Β· 2025β26</strong></div> |
| <div><span>Instructor</span><strong>Dr. Susham Biswas</strong></div> |
| <div><span>Institute</span><strong>RGIPT, Jais, Amethi</strong></div> |
| </div> |
| <div class="team-grid"> |
| <div class="team-card leader"> |
| <div class="card-role">β Team Leader</div> |
| <div class="card-name">Anurag Sharma</div> |
| <div class="card-roll">24MC3008</div> |
| <div class="card-desc">Project architecture, system integration, environment setup, and final submission. Coordinates all modules into a cohesive working application.</div> |
| </div> |
| <div class="team-card"> |
| <div class="card-role">Model Research</div> |
| <div class="card-name">Nityansh Pant</div> |
| <div class="card-roll">24MC3033</div> |
| <div class="card-desc">Deep-dives into Real-ESRGAN architecture, RRDB block design, and GAN theory. Responsible for literature review and model selection rationale.</div> |
| </div> |
| <div class="team-card"> |
| <div class="card-role">UI / UX Developer</div> |
| <div class="card-name">Vaibhav</div> |
| <div class="card-roll">24MC3059</div> |
| <div class="card-desc">Designs and implements the Gradio interface β layout, custom CSS theming, tab structure, and overall visual experience of the application.</div> |
| </div> |
| <div class="team-card"> |
| <div class="card-role">Image Preprocessing</div> |
| <div class="card-name">Shubhayu Brahmachari</div> |
| <div class="card-roll">24MC3046</div> |
| <div class="card-desc">Handles input validation, format conversion, colour space management, and post-processing of enhanced outputs before display.</div> |
| </div> |
| <div class="team-card"> |
| <div class="card-role">Inference Engine</div> |
| <div class="card-name">Himanshu Sachdeva</div> |
| <div class="card-roll">24MC3021</div> |
| <div class="card-desc">Implements model loading, tiling strategy, upsampler configuration, and CPU inference pipeline for efficient processing.</div> |
| </div> |
| <div class="team-card"> |
| <div class="card-role">Testing & Evaluation</div> |
| <div class="card-name">Arjit Anand</div> |
| <div class="card-roll">24MC3009</div> |
| <div class="card-desc">Conducts before/after quality comparisons, documents metrics, and validates model performance across different artwork styles.</div> |
| </div> |
| <div class="team-card"> |
| <div class="card-role">Documentation</div> |
| <div class="card-name">Taksh Agarwal</div> |
| <div class="card-roll">24MC3051</div> |
| <div class="card-desc">Writes the README, inline code documentation, report structure, and technical write-up covering methodology and results.</div> |
| </div> |
| <div class="team-card"> |
| <div class="card-role">Demo & Presentation</div> |
| <div class="card-name">Utkarsh Dixit</div> |
| <div class="card-roll">24MC3057</div> |
| <div class="card-desc">Records the video demonstration, coordinates individual narration segments, and prepares the final presentation for submission.</div> |
| </div> |
| </div> |
| </div> |
| """) |
|
|
| demo.launch(css=css) |
|
|