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:
76
src/anyimage/server/models/upscale.py
Normal file
76
src/anyimage/server/models/upscale.py
Normal 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
|
||||
Reference in New Issue
Block a user