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

@@ -1,16 +1,46 @@
from pathlib import Path
import bpy
from .runtime import DEFAULT_STORAGE_ROOT, runtime
from .properties import (
ai_setup_label,
ai_status,
device_enum_items,
model_catalog,
from .server.model_catalog import DEFAULT_UPSCALE_MODEL_KEY, UPSCALE_MODELS
ADDON_PACKAGE = __package__
DEFAULT_STORAGE_ROOT = Path.home() / ".anyimage"
DEFAULT_UPSCALE_MAX_OUTPUT_SIZE = 4096
MAX_UPSCALE_OUTPUT_SIZE = 8192
UPSCALE_MODEL_ITEMS = tuple(
(model.key, model.label, model.description, index)
for index, model in enumerate(UPSCALE_MODELS.values())
)
def addon_preferences(context=None):
preference_context = (
context
if getattr(context, "preferences", None) is not None
else bpy.context
)
addon = preference_context.preferences.addons.get(ADDON_PACKAGE)
return getattr(addon, "preferences", None)
def configured_storage_root():
configured = getattr(addon_preferences(), "storage_root", "")
if configured:
return Path(bpy.path.abspath(configured))
return DEFAULT_STORAGE_ROOT
def device_items(owner, context):
from .properties import device_enum_items
return device_enum_items(owner, context)
class AnyImagePreferences(bpy.types.AddonPreferences):
bl_idname = __package__
bl_idname = ADDON_PACKAGE
storage_root: bpy.props.StringProperty(
name="Storage Root",
@@ -27,14 +57,37 @@ class AnyImagePreferences(bpy.types.AddonPreferences):
"Inference device used by production tasks; only devices supported "
"on this machine are listed"
),
items=device_enum_items,
items=device_items,
default=0,
)
upscale_model: bpy.props.EnumProperty(
name="Default Upscale Model",
description="Model used when starting a new Upscale operation",
items=UPSCALE_MODEL_ITEMS,
default=DEFAULT_UPSCALE_MODEL_KEY,
)
upscale_max_output_size: bpy.props.IntProperty(
name="Maximum Upscale Size",
description=(
"Maximum output long edge; larger inputs are resized before 4x "
"upscaling to keep memory use bounded"
),
default=DEFAULT_UPSCALE_MAX_OUTPUT_SIZE,
min=1024,
max=MAX_UPSCALE_OUTPUT_SIZE,
step=256,
subtype="PIXEL",
)
def draw(self, _context):
from .properties import ai_setup_label, ai_status, model_catalog
from .runtime import runtime
layout = self.layout
layout.prop(self, "storage_root")
layout.prop(self, "device")
layout.prop(self, "upscale_model")
layout.prop(self, "upscale_max_output_size")
layout.separator()
status = ai_status()
layout.label(text=f"Environment: {runtime.environment_directory()}")
@@ -74,6 +127,8 @@ class AnyImagePreferences(bpy.types.AddonPreferences):
)
def _draw_model(self, layout, model):
from .runtime import runtime
row = layout.row(align=True)
row.label(text=model["label"])
if model.get("ready"):