import sys import torchvision.transforms.functional as F # Fix for basicsr error: redirect the old path to the new one sys.modules['torchvision.transforms.functional_tensor'] = F import os import gradio as gr # ... your other imports like from realesrgan import ... 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 # ── Load model ───────────────────────────────────────────────────────────────── 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." # Ensure scale is valid (2 or 4) scale = int(scale) if scale in [2, 4] else 4 # Resize large images for speed — cap at 256px on shortest side 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 ───────────────────────────────────────────────────────────────────────── 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; } """ # ── SVG: ESRGAN Pipeline ──────────────────────────────────────────────────────── esrgan_diagram = """ LOW-RES Input Image e.g. 64×64 px TILE SPLIT 256×256 tiles GENERATOR (RRDB Network) RRDB Block 1 RRDB Block 2 ··· RRDB Block 6 Dense skip connections · learns textures, edges & fine detail PIXEL SHUFFLE ×4 upscale TILE MERGE stitch tiles HIGH-RES Output Image 256×256 px """ # ── SVG: GAN Diagram ──────────────────────────────────────────────────────────── gan_diagram = """ LOW-RES IMAGE degraded input GENERATOR RRDB Network Creates fake HR image Tries to fool detector ↑ improved via feedback FAKE HR generated output REAL HR ground truth DISCRIMINATOR Is this real or fake? Scores both images Sends loss signal ↑ trains generator LOSS SCORE Real / Fake verdict Updates both networks training feedback loop — repeated millions of times """ # ── SVG: Loss Function Diagram ────────────────────────────────────────────────── loss_diagram = """ Total Loss L = Lp + λLadv + ηLperc Pixel Loss (L1 / MSE) pixel-by-pixel difference Adversarial Loss fool the discriminator Perceptual Loss (VGG) feature-level similarity Ensures structural fidelity Prevents totally wrong outputs Produces sharp, realistic textures Prevents blurry outputs Matches high-level features Preserves semantic content Result: Perceptually Sharp Structurally correct + photorealistic texture + semantically meaningful """ # ── UI ────────────────────────────────────────────────────────────────────────── with gr.Blocks(title="ArtUpscale — AI Super Resolution") as demo: gr.HTML(""" """) with gr.Tabs(elem_classes=["tab-nav"]): # ── TAB 1: ENHANCE ─────────────────────────────────────────────────── with gr.Tab("✦ Enhance"): gr.HTML("""
⚡ For fast demo results — use small artwork images (under 300×300px). Try anime thumbnails, pixel art, game sprites, or low-res manga panels. Processing time on CPU: ~8–15s for small images, ~30–60s for large ones.
Good test sources: Google Images → Tools → Size → Small Pinterest low-res art Game sprite sheets
""") 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("""
Tips for best results
· Anime, manga & illustrations → best output
· Pixel art → use 4× for crisp upscale
· Photos work too but are slower
· Start with 4× — it is the supported upscale
· The queue timer is normal — it's processing!
Good test images
anime thumbnail pixel art sprite manga panel game screenshot low-res painting
""") with gr.Column(scale=1, min_width=320): gr.HTML("""
⏳ Processing takes 10–60s on CPU · The queue timer below the image is normal · Please wait
""") 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("""
What just happened?
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.
""") 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]) # ── TAB 2: THE MODEL ───────────────────────────────────────────────── with gr.Tab("◈ The Model"): gr.HTML(f"""

Real-ESRGAN

Real-Enhanced Super-Resolution Generative Adversarial Network — a deep learning model that doesn't just stretch pixels, it invents 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.

Max Upscale
6B
RRDB Blocks
17M
Parameters
3
Loss Functions
What is a GAN? — The Forger & The Detective
{gan_diagram}
🎨
Generator — The Art Forger
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.
🔍
Discriminator — The Detective
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.
🔄
Adversarial Training Loop
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.
Why Not Just Bicubic?
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 interpolation vs learned perception.
ESRGAN Architecture & Pipeline
{esrgan_diagram}
🧱
RRDB — Residual-in-Residual Dense Blocks
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.
🔲
Tile-Based Inference
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.
📐
Pixel Shuffle Upscaling
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.
🎌
Anime 6B Variant
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.
Loss Functions — How the Model Learns
{loss_diagram}
📏
Pixel Loss (L1 / MSE)
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.
⚔️
Adversarial Loss
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.
🧠
Perceptual Loss (VGG Features)
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.
⚖️
Combined Loss = Best of All Three
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.
The Key Insight
Traditional methods ask "what pixel value makes mathematical sense here?" Real-ESRGAN asks "what would a human photographer actually have captured here?" 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.
""") # ── TAB 3: TEAM ───────────────────────────────────────────────────── with gr.Tab("◉ Our Team"): gr.HTML("""
CourseCS360 · Artificial Intelligence
Semester4th Semester · 2025–26
InstructorDr. Susham Biswas
InstituteRGIPT, Jais, Amethi
⭐ Team Leader
Anurag Sharma
24MC3008
Project architecture, system integration, environment setup, and final submission. Coordinates all modules into a cohesive working application.
Model Research
Nityansh Pant
24MC3033
Deep-dives into Real-ESRGAN architecture, RRDB block design, and GAN theory. Responsible for literature review and model selection rationale.
UI / UX Developer
Vaibhav
24MC3059
Designs and implements the Gradio interface — layout, custom CSS theming, tab structure, and overall visual experience of the application.
Image Preprocessing
Shubhayu Brahmachari
24MC3046
Handles input validation, format conversion, colour space management, and post-processing of enhanced outputs before display.
Inference Engine
Himanshu Sachdeva
24MC3021
Implements model loading, tiling strategy, upsampler configuration, and CPU inference pipeline for efficient processing.
Testing & Evaluation
Arjit Anand
24MC3009
Conducts before/after quality comparisons, documents metrics, and validates model performance across different artwork styles.
Documentation
Taksh Agarwal
24MC3051
Writes the README, inline code documentation, report structure, and technical write-up covering methodology and results.
Demo & Presentation
Utkarsh Dixit
24MC3057
Records the video demonstration, coordinates individual narration segments, and prepares the final presentation for submission.
""") demo.launch(css=css)