upscale
Upscale images 2x, 3x or 4x with Real-ESRGAN (ncnn-vulkan) using three selectable models โ no CUDA required.
Downloads: 8 ยท ID: 26461da05c48d7445d000000
Upscale images 2x, 3x or 4x with Real-ESRGAN (ncnn-vulkan) using three selectable models โ no CUDA required.
Downloads: 8 ยท ID: 26461da05c48d7445d000000
<!-- FILE: upscale_skill.md -->
# Image Upscaling Skill
Upscales images using **Real-ESRGAN** (`realesrgan-ncnn-vulkan`) โ a portable, GPU-accelerated (or CPU fallback) upscaler. **Fully self-contained** โ binary and models live in this directory. No CUDA or PyTorch needed.
```
python upscale_image.py <input> [options]
```
## Models
| Model | Best for | Size |
|-------|----------|------|
| `realesr-animevideov3` (default) | Anime, cartoons, illustrations โ fast | 1.2 MB |
| `realesrgan-x4plus` | General photos, realistic imagery โ highest quality | 32 MB |
| `realesrgan-x4plus-anime` | Anime/art, better than v3 but slower | 8.5 MB |
## Args
| Arg | Default | Description |
|-----|---------|-------------|
| `input` | **required** | Input image path or directory |
| `-o`, `--output` | `~/Pictures/upscaled/` | Output path (file or directory) |
| `-s`, `--scale` | `4` | Upscale ratio: `2`, `3`, or `4` |
| `-n`, `--model` | `realesr-animevideov3` | Model name (see table above) |
| `-f`, `--format` | `png` | Output format: `jpg`, `png`, `webp` |
| `-t`, `--tile` | `0` (auto) | Tile size for processing. Increase if you run out of memory |
| `-x`, `--tta` | off | TTA mode โ slower but slightly better quality |
| `-v`, `--verbose` | off | Show Real-ESRGAN progress output |
## Output
Prints the output path + `<img>` tag to stdout (single image mode):
```
~/Pictures/upscaled/photo_x4_1712345678.png
<img src="file://~/Pictures/upscaled/photo_x4_1712345678.png" alt="upscaled photo_x4_1712345678.png">
```
In batch mode (directory input), prints the output directory path.
## Examples
```bash
# Simple upscale (2x with anime model, to ~/Pictures/upscaled/)
python upscale_image.py vacation_photo.jpg -s 2
# Maximum quality photo upscale (4x with the big model)
python upscale_image.py portrait.png -s 4 -n realesrgan-x4plus -o hq_portrait.png
# Anime upscale (4x with anime-tuned model)
python upscale_image.py sketch.png -s 4 -n realesrgan-x4plus-anime
# Web-friendly JPEG output
python upscale_image.py photo.jpg -s 2 -f jpg -o ~/Desktop/
# Batch upscale an entire directory
python upscale_image.py input_frames/ -o upscaled_frames/ -s 2 -f jpg
# TTA mode for best quality (slower)
python upscale_image.py precious_photo.png -s 4 -n realesrgan-x4plus -x
```
## Dependencies
The skill vendors the `realesrgan-ncnn-vulkan` binary and model files directly in the skill directory.
No Python ML libraries or CUDA needed โ the binary uses Vulkan for GPU acceleration.
If you see `ERROR: Real-ESRGAN binary not found`, the binary is missing. To fix:
```bash
# Option 1: Download from releases
cd ~/skills/upscale
wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesrgan-ncnn-vulkan-20230429-ubuntu.zip
unzip -o realesrgan-ncnn-vulkan-*.zip && rm *.zip
# Option 2: Symlink an existing installation
ln -s /path/to/realesrgan-ncnn-vulkan ~/skills/upscale/realesrgan-ncnn-vulkan
```
## Notes
- Uses your GPU if available (Intel, NVIDIA, AMD via Vulkan). Falls back to CPU.
- The binary tiles large images to save memory. Adjust `-t` if you hit memory limits.
- PNG output preserves quality; use JPEG for smaller files.
<!-- FILE: upscale_image.py -->
#!/usr/bin/env python3
"""Upscale images using Real-ESRGAN (ncnn-vulkan, no GPU required).
Vendored binary + models in this directory. No Python ML deps needed."""
import argparse, os, subprocess, sys, time
from pathlib import Path
SKILL_DIR = Path(__file__).parent
BINARY = SKILL_DIR / "realesrgan-ncnn-vulkan"
MODELS_DIR = SKILL_DIR / "models"
AVAILABLE_MODELS = [
"realesr-animevideov3", # default, fast, good for anime/cartoons
"realesrgan-x4plus", # general photo upscaling (best quality)
"realesrgan-x4plus-anime", # tuned for anime style
]
def _check_binary():
"""Verify the Real-ESRGAN binary and models exist."""
if not BINARY.exists():
print(f"ERROR: Real-ESRGAN binary not found at: {BINARY}", file=sys.stderr)
print(file=sys.stderr)
print("The upscale skill vendors realesrgan-ncnn-vulkan in the skill directory.", file=sys.stderr)
print(file=sys.stderr)
print("To set it up:", file=sys.stderr)
print(f" 1. Download from https://github.com/xinntao/Real-ESRGAN/releases", file=sys.stderr)
print(f" 2. Place the binary at: {BINARY}", file=sys.stderr)
print(f" 3. Place models in: {MODELS_DIR}/", file=sys.stderr)
print(file=sys.stderr)
print("Or symlink an existing installation:", file=sys.stderr)
print(f" ln -s /path/to/realesrgan-ncnn-vulkan {BINARY}", file=sys.stderr)
sys.exit(1)
if not MODELS_DIR.exists():
print(f"ERROR: Real-ESRGAN models directory not found at: {MODELS_DIR}", file=sys.stderr)
print("The skill ships with models bundled in the git repo.", file=sys.stderr)
print("Try: git lfs pull # if models are stored with LFS", file=sys.stderr)
sys.exit(1)
_check_binary()
def resolve_output(input_path, scale, output_arg):
"""Determine output path."""
stem = input_path.stem
ext = ".png" # default output
if output_arg:
out = Path(output_arg)
if out.is_dir():
out = out / f"{stem}_x{scale}.png"
return out
base = Path.home() / "Pictures" / "upscaled"
base.mkdir(parents=True, exist_ok=True)
return base / f"{stem}_x{scale}_{int(time.time())}.png"
def main():
p = argparse.ArgumentParser(
description="Upscale images using Real-ESRGAN (ncnn-vulkan)",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=f"""\
Available models: {', '.join(AVAILABLE_MODELS)}
Examples:
%(prog)s input.jpg
%(prog)s input.png -o output.png -s 4 -n realesrgan-x4plus
%(prog)s input.jpg -s 2 -f jpg -n realesr-animevideov3
%(prog)s input_folder/ -o output_folder/ -s 4""",
)
p.add_argument("input", help="Input image path or directory")
p.add_argument("-o", "--output", default="",
help="Output path (file or directory). Default: ~/Pictures/upscaled/")
p.add_argument("-s", "--scale", type=int, default=4, choices=[2, 3, 4],
help="Upscale ratio (default: 4)")
p.add_argument("-n", "--model", default="realesr-animevideov3",
choices=AVAILABLE_MODELS,
help="Model name (default: realesr-animevideov3)")
p.add_argument("-f", "--format", default="png", choices=["jpg", "png", "webp"],
help="Output image format (default: png)")
p.add_argument("-t", "--tile", type=int, default=0,
help="Tile size (0=auto, default: 0)")
p.add_argument("-x", "--tta", action="store_true",
help="Enable TTA mode (slower but slightly better quality)")
p.add_argument("-v", "--verbose", action="store_true",
help="Show realesrgan verbose output")
a = p.parse_args()
input_path = Path(a.input)
if not input_path.exists():
print(f"ERROR: input not found: {a.input}", file=sys.stderr)
sys.exit(1)
# Resolve output
output_path = resolve_output(input_path, a.scale, a.output)
# Build command
cmd = [
str(BINARY),
"-i", str(input_path),
"-o", str(output_path),
"-s", str(a.scale),
"-m", str(MODELS_DIR),
"-n", a.model,
"-f", a.format,
"-t", str(a.tile),
]
if a.tta:
cmd.append("-x")
if a.verbose:
cmd.append("-v")
# Print what we're doing
name_tag = f"{a.model} x{a.scale}"
if input_path.is_dir():
print(f"Batch upscaling: {input_path} โ {output_path} [{name_tag}]", file=sys.stderr)
else:
print(f"Upscaling: {input_path.name} โ {output_path} [{name_tag}]", file=sys.stderr)
# Run
result = subprocess.run(cmd, capture_output=not a.verbose, text=True)
if result.returncode != 0:
print(f"ERROR: Real-ESRGAN failed (exit {result.returncode})", file=sys.stderr)
if result.stderr:
print(result.stderr.strip(), file=sys.stderr)
sys.exit(1)
# Report output
if input_path.is_dir():
print(f"Done: {output_path}")
else:
print(output_path)
alt = f"upscaled {output_path.name}"
print(f'<img src="file://{output_path}" alt="{alt}">')
if __name__ == "__main__":
main()