BerhaneW's picture
Added ml project
c4a8c0e verified
Raw History Blame Contribute Delete
5.68 kB
import argparse
import sys
from pathlib import Path
import numpy as np
import tensorflow as tf
from PIL import Image
sys.path.insert(0, str(Path(__file__).parent))
from model import PixelShuffle
def upscale(
input_path,
checkpoint_path=None,
output_path=None,
comparison_path=None,
scale=2,
arch='espcn',
checkpoint_dir='outputs/checkpoints',
):
"""
Upscale a single image using a trained ESPCN/SRCNN model.
Parameters
----------
input_path : path to the low-resolution input image
checkpoint_path : path to the .keras model file
if None, auto-loads from checkpoint_dir using arch + scale
output_path : where to save the SR image
comparison_path : where to save a side-by-side comparison image
scale : upscale factor (2, 3, 4, or 8)
arch : model architecture — 'espcn' or 'srcnn'
checkpoint_dir : folder containing trained checkpoints
"""
input_path = Path(input_path)
if checkpoint_path is None:
checkpoint_path = Path(checkpoint_dir) / f"{arch}_x{scale}_best.keras"
else:
checkpoint_path = Path(checkpoint_path)
if not checkpoint_path.exists():
raise FileNotFoundError(f"Checkpoint not found: {checkpoint_path}")
model = tf.keras.models.load_model(
checkpoint_path,
custom_objects={'PixelShuffle': PixelShuffle},
compile=False,
)
print(f"Loaded : {checkpoint_path} ({arch.upper()}, x{scale})")
lr_img = Image.open(input_path).convert('RGB')
orig_w, orig_h = lr_img.size
print(f"Input : {input_path} ({orig_w}×{orig_h})")
lr_arr = np.array(lr_img, dtype=np.float32) / 255.0
lr_tensor = lr_arr[np.newaxis, ...] # (1, H, W, 3)
if arch == 'srcnn':
lr_tensor = tf.image.resize(
lr_tensor,
[orig_h * scale, orig_w * scale],
method='bicubic'
).numpy()
lr_tensor = np.clip(lr_tensor, 0.0, 1.0)
sr_arr = model.predict(lr_tensor, verbose=0)[0]
sr_arr = np.clip(sr_arr, 0.0, 1.0)
sr_img = Image.fromarray((sr_arr * 255).astype(np.uint8))
sr_w, sr_h = sr_img.size
input_stem = input_path.stem
input_ext = input_path.suffix if input_path.suffix else '.png'
if output_path is None:
output_path = input_path.parent / f"{input_stem}_{arch}_x{scale}_sr{input_ext}"
else:
output_path = Path(output_path)
sr_img.save(output_path)
print(f"SR image: {output_path} ({sr_w}×{sr_h})")
# Bicubic baseline for comparison
bicubic_img = lr_img.resize((orig_w * scale, orig_h * scale), Image.BICUBIC)
# Resize LR preview so all three panels match in displayed size
lr_preview = lr_img.resize((orig_w * scale, orig_h * scale), Image.NEAREST)
padding = 12
label_space = 28
panel_w = lr_preview.width
panel_h = lr_preview.height
comp_w = panel_w * 3 + padding * 4
comp_h = panel_h + padding * 2 + label_space
comparison = Image.new('RGB', (comp_w, comp_h), (30, 30, 30))
x = padding
y = padding
comparison.paste(lr_preview, (x, y))
x += panel_w + padding
comparison.paste(bicubic_img, (x, y))
x += panel_w + padding
comparison.paste(sr_img, (x, y))
try:
from PIL import ImageDraw
draw = ImageDraw.Draw(comparison)
labels = [
(padding, panel_h + padding + 6, 'LR Input'),
(panel_w + padding * 2, panel_h + padding + 6, 'Bicubic'),
(panel_w * 2 + padding * 3, panel_h + padding + 6, f'{arch.upper()} x{scale}'),
]
for lx, ly, text in labels:
draw.text((lx, ly), text, fill=(220, 220, 220))
except Exception as e:
print(f"Warning: could not draw labels on comparison image: {e}")
if comparison_path is None:
comparison_path = input_path.parent / f"{input_stem}_{arch}_x{scale}_compare{input_ext}"
else:
comparison_path = Path(comparison_path)
comparison.save(comparison_path)
print(f"Compare : {comparison_path} (LR | Bicubic | {arch.upper()} x{scale})")
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Upscale a single image with a trained ESPCN/SRCNN model'
)
parser.add_argument(
'--input',
type=str,
required=True,
help='Path to the low-resolution input image'
)
parser.add_argument(
'--checkpoint',
type=str,
default=None,
help='Optional path to .keras model file; if omitted, uses outputs/checkpoints/{arch}_x{scale}_best.keras'
)
parser.add_argument(
'--checkpoint_dir',
type=str,
default='outputs/checkpoints',
help='Directory containing trained checkpoints'
)
parser.add_argument(
'--output',
type=str,
default=None,
help='Output path for the SR image'
)
parser.add_argument(
'--comparison',
type=str,
default=None,
help='Output path for the side-by-side comparison image'
)
parser.add_argument(
'--scale',
type=int,
default=2,
choices=[2, 3, 4, 8],
help='Upscale factor'
)
parser.add_argument(
'--arch',
type=str,
default='espcn',
choices=['espcn', 'srcnn'],
help='Model architecture'
)
args = parser.parse_args()
upscale(
input_path=args.input,
checkpoint_path=args.checkpoint,
output_path=args.output,
comparison_path=args.comparison,
scale=args.scale,
arch=args.arch,
checkpoint_dir=args.checkpoint_dir,
)