Spaces:
Build error
Build error
File size: 6,420 Bytes
d57628d 5da7b96 81952ce 0627e00 81952ce 0627e00 81952ce 5da7b96 81952ce 0627e00 81952ce 0627e00 5da7b96 81952ce 0627e00 81952ce d57628d 81952ce | 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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | import gradio as gr
import numpy as np
from PIL import Image
import io
import torch
import torchvision.transforms as T
# -----------------------------
# GLOBAL FLAGS / DEVICE
# -----------------------------
DEVICE = "cpu" # Force CPU for Hugging Face CPU Basic
# -----------------------------
# TEST MODE (your existing lightweight placeholder)
# -----------------------------
def test_mode_colorize(pil_img: Image.Image) -> Image.Image:
"""
Very lightweight "test" colorizer.
Just adds a tiny warm tint so we know the pipeline works.
"""
img = pil_img.convert("RGB")
arr = np.array(img).astype(np.float32) / 255.0
# Subtle warm tint
tint = np.array([1.02, 1.0, 0.98], dtype=np.float32)
arr = np.clip(arr * tint, 0.0, 1.0)
arr = (arr * 255).astype(np.uint8)
return Image.fromarray(arr)
# -----------------------------
# ZHANG ECCV16 COLORIZER (CPU)
# -----------------------------
# We use the lightweight PyTorch implementation from richzhang/colorization
# via the rz-colorization package (CPU‑friendly).
try:
import colorizers # from rz-colorization or richzhang/colorization
_ZHANG_AVAILABLE = True
except Exception:
_ZHANG_AVAILABLE = False
colorizers = None
_zhang_model = None
_zhang_transform = T.Compose([
T.Resize(256),
T.CenterCrop(256),
T.ToTensor(),
])
def load_zhang_model():
global _zhang_model
if not _ZHANG_AVAILABLE:
return None
if _zhang_model is None:
# ECCV16 model = fully automatic colorization
_zhang_model = colorizers.eccv16().eval().to(DEVICE)
return _zhang_model
def zhang_colorize(pil_img: Image.Image) -> Image.Image:
"""
Use Zhang ECCV16 model to colorize a grayscale image.
Stronger, real colorization. CPU‑friendly.
"""
model = load_zhang_model()
if model is None:
# Fallback: if model not available, just return test mode result
return test_mode_colorize(pil_img)
# Convert to RGB then to Lab
img = pil_img.convert("RGB")
img_resized = _zhang_transform(img) # [3, H, W] in [0,1]
img_resized = img_resized.unsqueeze(0).to(DEVICE)
# Convert to Lab
from skimage import color as skcolor
np_img = img_resized[0].permute(1, 2, 0).cpu().numpy()
lab = skcolor.rgb2lab(np_img)
L = lab[:, :, 0] # [H, W]
tens_l = torch.from_numpy(L).unsqueeze(0).unsqueeze(0).float().to(DEVICE)
with torch.no_grad():
out_ab = model(tens_l).cpu() # [1, 2, H, W]
out_ab = out_ab[0].permute(1, 2, 0).numpy() # [H, W, 2]
# Resize ab to original image size
H_orig, W_orig = img.size[1], img.size[0]
out_ab_resized = np.array(
Image.fromarray((out_ab * 255).astype(np.uint8)).resize((W_orig, H_orig), Image.BILINEAR),
dtype=np.float32
) / 255.0
# Rebuild Lab image at original resolution
img_np = np.array(img).astype(np.float32) / 255.0
lab_orig = skcolor.rgb2lab(img_np)
L_orig = lab_orig[:, :, 0]
lab_out = np.zeros((H_orig, W_orig, 3), dtype=np.float32)
lab_out[:, :, 0] = L_orig
lab_out[:, :, 1:] = out_ab_resized * 128.0 # scale back
rgb_out = skcolor.lab2rgb(lab_out)
rgb_out = np.clip(rgb_out, 0.0, 1.0)
rgb_out = (rgb_out * 255).astype(np.uint8)
return Image.fromarray(rgb_out)
# -----------------------------
# DEOLDIFY‑LITE (ART MODE, CPU)
# -----------------------------
# For CPU Basic, we implement a "lite" DeOldify‑style effect:
# stronger saturation + learned‑like color shift, but still lightweight.
def deoldify_lite_colorize(pil_img: Image.Image) -> Image.Image:
"""
CPU‑safe "DeOldify‑Lite" style:
- Convert to RGB
- Apply stronger contrast + saturation
- Apply learned‑like color mapping in Lab space
"""
img = pil_img.convert("RGB")
arr = np.array(img).astype(np.float32) / 255.0
# Convert to Lab
from skimage import color as skcolor
lab = skcolor.rgb2lab(arr)
L = lab[:, :, 0]
a = lab[:, :, 1]
b = lab[:, :, 2]
# Boost chroma (a,b) to simulate stronger colorization
a *= 1.35
b *= 1.35
# Gentle bias toward warmer tones
a += 2.0
b += 1.0
lab_out = np.stack([L, a, b], axis=-1)
rgb_out = skcolor.lab2rgb(lab_out)
rgb_out = np.clip(rgb_out, 0.0, 1.0)
rgb_out = (rgb_out * 255).astype(np.uint8)
return Image.fromarray(rgb_out)
# -----------------------------
# MAIN PIPELINE
# -----------------------------
def colorize_image(input_image, mode):
if input_image is None:
return None
pil_img = input_image.convert("RGB")
if mode == "Test Mode (Very Subtle)":
out = test_mode_colorize(pil_img)
elif mode == "Zhang ECCV16 (Deep Colorizer)":
out = zhang_colorize(pil_img)
elif mode == "DeOldify‑Lite (Art Mode)":
out = deoldify_lite_colorize(pil_img)
else:
out = test_mode_colorize(pil_img)
return out
# -----------------------------
# GRADIO UI
# -----------------------------
with gr.Blocks(title="Fast CPU Biker Image Colorizer (Test + Zhang + DeOldify‑Lite)") as demo:
gr.Markdown(
"""
# Fast CPU Biker Image Colorizer (Test + Zhang + DeOldify‑Lite)
**App 1 – Colorizer**
- Runs entirely on **CPU Basic**
- Three modes:
- **Test Mode (Very Subtle)** – your original placeholder
- **Zhang ECCV16 (Deep Colorizer)** – real neural colorization
- **DeOldify‑Lite (Art Mode)** – stronger, art‑style color
Upload a grayscale or sketch image on the left, choose a mode, then click **Colorize**.
"""
)
with gr.Row():
with gr.Column():
input_image = gr.Image(type="pil", label="Input Image")
mode = gr.Radio(
choices=[
"Test Mode (Very Subtle)",
"Zhang ECCV16 (Deep Colorizer)",
"DeOldify‑Lite (Art Mode)",
],
value="Zhang ECCV16 (Deep Colorizer)",
label="Colorization Mode",
)
run_btn = gr.Button("Colorize", variant="primary")
with gr.Column():
output_image = gr.Image(type="pil", label="Output Image")
run_btn.click(
fn=colorize_image,
inputs=[input_image, mode],
outputs=[output_image],
)
if __name__ == "__main__":
demo.launch()
|