Spaces:
Sleeping
Sleeping
File size: 6,216 Bytes
c853df8 6010e75 58278dc c853df8 3caa18a c853df8 6010e75 3caa18a c853df8 6010e75 3caa18a 6010e75 3caa18a 58278dc 3caa18a 6010e75 58278dc 6010e75 c853df8 3caa18a c853df8 3caa18a c853df8 3caa18a c853df8 3caa18a c853df8 3caa18a c853df8 3caa18a c853df8 3caa18a c853df8 3caa18a c853df8 3caa18a c853df8 3caa18a c853df8 3caa18a c853df8 3caa18a ab2e507 c853df8 6010e75 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | import os
import math
import numpy as np
import onnxruntime as ort
from PIL import Image
import gradio as gr
from huggingface_hub import hf_hub_download
import shutil
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# 1) Auto-Download Ultra-Fast Model
MODEL_DIR = "model"
os.makedirs(MODEL_DIR, exist_ok=True)
MODEL_X4_PATH = os.path.join(MODEL_DIR, "realesr-general-x4v3.onnx")
def fetch_models():
"""Downloads the 4.8MB ultra-lightweight model from an open repository."""
if not os.path.exists(MODEL_X4_PATH):
print("Downloading 4.8MB High-Speed Real-ESRGAN model...")
downloaded_path = hf_hub_download(
repo_id="OwlMaster/AllFilesRope",
filename="realesr-general-x4v3.onnx"
)
shutil.copy(downloaded_path, MODEL_X4_PATH)
print("Model downloaded successfully!")
fetch_models()
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# 2) Efficient CPU Session
sess_opts = ort.SessionOptions()
sess_opts.intra_op_num_threads = 2
sess_opts.inter_op_num_threads = 2
session_x4 = None
def load_model():
global session_x4
if session_x4 is None:
session_x4 = ort.InferenceSession(MODEL_X4_PATH, sess_options=sess_opts, providers=["CPUExecutionProvider"])
return session_x4
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# 3) Adaptive Tiling Engine
def process_tensor(session, tensor_np):
input_name = session.get_inputs()[0].name
patch_nchw = np.transpose(tensor_np, (2, 0, 1))[np.newaxis, ...]
out_nchw = session.run(None, {input_name: patch_nchw})[0]
out_nchw = np.squeeze(out_nchw, axis=0)
return np.transpose(out_nchw, (1, 2, 0))
def dynamic_upscale(input_img: Image.Image, target_scale: int, progress=gr.Progress()):
session = load_model()
base_model_scale = 4
img_rgb = input_img.convert("RGB")
arr = np.array(img_rgb).astype(np.float32) / 255.0
h_orig, w_orig, _ = arr.shape
# 16GB RAM can safely process up to ~1500x1500px in one shot without tiling.
MAX_NO_TILE_DIM = 1500
if max(h_orig, w_orig) <= MAX_NO_TILE_DIM:
progress(0.4, desc="RAM check passed. Processing full image instantly...")
out_arr = process_tensor(session, arr)
else:
# For huge images, we use large 800px tiles to minimize loop overhead
tile_size = 800
tiles_h = math.ceil(h_orig / tile_size)
tiles_w = math.ceil(w_orig / tile_size)
pad_h = tiles_h * tile_size - h_orig
pad_w = tiles_w * tile_size - w_orig
arr_padded = np.pad(arr, ((0, pad_h), (0, pad_w), (0, 0)), mode="reflect")
out_h = tiles_h * tile_size * base_model_scale
out_w = tiles_w * tile_size * base_model_scale
out_arr = np.zeros((out_h, out_w, 3), dtype=np.float32)
total_tiles = tiles_h * tiles_w
current_tile = 0
for i in range(tiles_h):
for j in range(tiles_w):
current_tile += 1
progress(current_tile / total_tiles, desc=f"AI Processing tile {current_tile}/{total_tiles}...")
y0, x0 = i * tile_size, j * tile_size
tile = arr_padded[y0:y0+tile_size, x0:x0+tile_size, :]
up_tile = process_tensor(session, tile)
oy0, ox0 = i * tile_size * base_model_scale, j * tile_size * base_model_scale
out_arr[oy0:oy0 + tile_size * base_model_scale, ox0:ox0 + tile_size * base_model_scale, :] = up_tile
out_arr = out_arr[0:h_orig * base_model_scale, 0:w_orig * base_model_scale, :]
# Finalize Image
progress(0.8, desc="Finalizing output...")
out_arr = np.clip(out_arr, 0.0, 1.0)
final_pil = Image.fromarray((out_arr * 255.0).round().astype(np.uint8))
# Downscale if the user requested 2x (from the 4x native output)
if target_scale != 4:
progress(0.9, desc=f"Refining output to {target_scale}x...")
target_size = (w_orig * target_scale, h_orig * target_scale)
final_pil = final_pil.resize(target_size, resample=Image.LANCZOS)
return final_pil
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# 4) UI Setup
def upscale_2x(img, prog=gr.Progress()): return dynamic_upscale(img, 2, prog) if img else None
def upscale_4x(img, prog=gr.Progress()): return dynamic_upscale(img, 4, prog) if img else None
def upscale_6x(img, prog=gr.Progress()): return dynamic_upscale(img, 6, prog) if img else None
css = """
#x2-btn { background-color: #d1fae5 !important; color: black !important; }
#x4-btn { background-color: #bfdbfe !important; color: black !important; }
#x6-btn { background-color: #fef08a !important; color: black !important; }
"""
with gr.Blocks(title="Speed-Optimized CPU Upscaler") as demo:
gr.Markdown("# β‘ Adaptive CPU Upscaler\nUpload an image. Great For Anime/Cartoon/Text , Very Fast . This app dynamically allocates RAM to bypass tiling for smaller images, running significantly faster on the Free Tier.")
with gr.Row(): inp_image = gr.Image(type="pil", label="Source Image")
with gr.Row():
btn_x2 = gr.Button("Upscale (Γ2)", elem_id="x2-btn")
btn_x4 = gr.Button("Standard AI (Γ4)", elem_id="x4-btn")
btn_x6 = gr.Button("Hybrid High-Res (Γ6)", elem_id="x6-btn")
out_preview = gr.Image(type="pil", label="Upscaled Result")
btn_x2.click(fn=upscale_2x, inputs=inp_image, outputs=out_preview)
btn_x4.click(fn=upscale_4x, inputs=inp_image, outputs=out_preview)
btn_x6.click(fn=upscale_6x, inputs=inp_image, outputs=out_preview)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860, css=css) |