feat: Implement upscale functionality with ONNX models

- Added upscale operator to handle image upscaling by 4x using AI models.
- Introduced new jobs for upscale processing in the server, including debug and standard upscale jobs.
- Created a new ONNX model handler for upscale operations, supporting tiled inference and resource management.
- Updated tests to cover new upscale functionality, including input validation and output verification.
- Added documentation for the upscale feature, detailing usage and model options.
This commit is contained in:
2026-08-23 20:34:35 +08:00
parent 1613bd3194
commit 0cf04a13c6
66 changed files with 2156 additions and 1088 deletions

View File

@@ -0,0 +1,76 @@
import math
SCALE = 4
MAX_OUTPUT_SIZE = 8192
MAX_OUTPUT_PIXELS = 32 * 1024 * 1024
def _limited_input(image, max_output_size):
from PIL import Image
max_output_size = int(max_output_size)
if max_output_size < 1 or max_output_size > MAX_OUTPUT_SIZE:
raise ValueError(
f"Max Output Size must be between 1 and {MAX_OUTPUT_SIZE} pixels"
)
width, height = image.size
scale = min(
1.0,
max_output_size / (max(width, height) * SCALE),
math.sqrt(MAX_OUTPUT_PIXELS / (width * height * SCALE * SCALE)),
)
if scale >= 1.0:
return image
size = (
max(1, int(width * scale)),
max(1, int(height * scale)),
)
return image.resize(size, Image.Resampling.LANCZOS)
def _source_alpha(image):
if "A" not in image.getbands() and "transparency" not in image.info:
return None
return image.convert("RGBA").getchannel("A")
def infer_one(
model_manager,
parameters,
image_path,
cancel_check=None,
preserve_alpha=False,
):
from PIL import Image
from .onnx_upscale import UpscaleResourceError, infer
model_directory = model_manager.directory(parameters["model"])
model = model_manager.get_upscale(
model_directory,
parameters["device"],
)
try:
with Image.open(image_path) as opened:
source = opened
if "max_output_size" in parameters:
source = _limited_input(source, parameters["max_output_size"])
source_alpha = _source_alpha(source) if preserve_alpha else None
prediction = infer(model, source, cancel_check=cancel_check)
if source_alpha is None:
return prediction
alpha = source_alpha.resize(
prediction.size,
Image.Resampling.LANCZOS,
)
prediction = prediction.convert("RGBA")
prediction.putalpha(alpha)
return prediction
except (MemoryError, UnicodeDecodeError, UpscaleResourceError) as error:
model_manager.release_upscale()
device = str(parameters.get("device", "selected device")).upper()
raise RuntimeError(
f"Upscale could not finish on {device}: {error}. "
"Reduce Max Output Size or select CPU, then try again."
) from error