Files
AnyImage/tests/test_upscale_onnx.py
nan 0cf04a13c6 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.
2026-08-23 20:34:35 +08:00

141 lines
4.3 KiB
Python

import sys
import unittest
from pathlib import Path
from types import SimpleNamespace
import numpy as np
from PIL import Image
SOURCE_DIR = (
Path(__file__).resolve().parents[1]
/ "src"
/ "anyimage"
/ "server"
/ "models"
)
sys.path.insert(0, str(SOURCE_DIR))
import onnx_upscale
class FakeSession:
def get_inputs(self):
return [SimpleNamespace(name="input")]
def get_outputs(self):
return [SimpleNamespace(name="output")]
def run(self, output_names, feeds):
self.output_names = output_names
self.feeds = feeds
source = feeds["input"]
return [np.repeat(np.repeat(source, 4, axis=2), 4, axis=3)]
class UpscaleOnnxTest(unittest.TestCase):
def test_preprocess_matches_dynamic_rgb_layout(self):
image = Image.new("RGB", (7, 5), (64, 128, 192))
result = onnx_upscale.preprocess(image)
self.assertEqual(result.shape, (1, 3, 5, 7))
self.assertEqual(result.dtype, np.float32)
self.assertTrue(result.flags.c_contiguous)
np.testing.assert_allclose(
result[0, :, 0, 0],
np.array((64, 128, 192), dtype=np.float32) / 255.0,
)
def test_infer_returns_direct_four_x_rgb_prediction(self):
session = FakeSession()
image = Image.new("RGB", (7, 5), (10, 20, 30))
result = onnx_upscale.infer(session, image)
self.assertEqual(result.mode, "RGB")
self.assertEqual(result.size, (28, 20))
self.assertEqual(session.output_names, ["output"])
self.assertEqual(session.feeds["input"].shape, (1, 3, 256, 256))
self.assertEqual(result.getpixel((0, 0)), (10, 20, 30))
def test_infer_returns_raw_rgb_for_rgba_input(self):
session = FakeSession()
pixels = np.zeros((5, 7, 4), dtype=np.uint8)
pixels[..., :3] = (10, 20, 30)
pixels[..., 3] = np.arange(7, dtype=np.uint8) * 40
image = Image.fromarray(pixels, mode="RGBA")
result = onnx_upscale.infer(session, image)
self.assertEqual(result.mode, "RGB")
self.assertEqual(result.size, (28, 20))
self.assertEqual(result.getpixel((0, 0)), (10, 20, 30))
def test_tiles_use_reflected_context_at_outer_image_edges(self):
class RecordingSession(FakeSession):
def run(self, output_names, feeds):
self.input = feeds["input"].copy()
return super().run(output_names, feeds)
pixels = np.zeros((5, 7, 3), dtype=np.uint8)
pixels[..., 0] = np.arange(7, dtype=np.uint8) * 20
session = RecordingSession()
onnx_upscale.infer(
session,
Image.fromarray(pixels, mode="RGB"),
)
red = session.input[0, 0]
self.assertAlmostEqual(red[16, 22], 120 / 255.0)
self.assertAlmostEqual(red[16, 23], 100 / 255.0)
def test_infer_rejects_non_four_x_output(self):
class InvalidSession(FakeSession):
def run(self, _output_names, feeds):
return [feeds["input"]]
with self.assertRaisesRegex(RuntimeError, "unexpected output shape"):
onnx_upscale.infer(
InvalidSession(),
Image.new("RGB", (7, 5)),
)
def test_all_models_split_large_inputs_into_fixed_tiles(self):
class CountingSession(FakeSession):
def __init__(self):
self.calls = 0
def run(self, output_names, feeds):
self.calls += 1
return super().run(output_names, feeds)
session = CountingSession()
result = onnx_upscale.infer(
session,
Image.new("RGB", (449, 225), (1, 2, 3)),
)
self.assertEqual(result.size, (1796, 900))
self.assertEqual(session.calls, 6)
self.assertEqual(session.feeds["input"].shape, (1, 3, 256, 256))
def test_provider_unicode_error_is_presented_as_resource_error(self):
class InvalidProviderSession(FakeSession):
def run(self, _output_names, _feeds):
raise UnicodeDecodeError("utf-8", b"\xc4", 0, 1, "invalid")
with self.assertRaisesRegex(
onnx_upscale.UpscaleResourceError,
"provider failed",
):
onnx_upscale.infer(
InvalidProviderSession(),
Image.new("RGB", (7, 5)),
)
if __name__ == "__main__":
unittest.main()