Разработка AI-аутпейнтинга для расширения изображений
Аутпейнтинг расширяет изображение за его исходные границы, органично заполняя новую область содержимым, соответствующим оригиналу. Применяется для создания широкоформатных баннеров из квадратных фото, расширения пространства вокруг объекта, создания панорам.
diffusers аутпейнтинг
from diffusers import StableDiffusionXLInpaintPipeline
from PIL import Image, ImageOps
import torch
import numpy as np
import io
class OutpaintingService:
def __init__(self):
self.pipe = StableDiffusionXLInpaintPipeline.from_pretrained(
"diffusers/stable-diffusion-xl-1.0-inpainting-0.1",
torch_dtype=torch.float16
).to("cuda")
def extend_image(
self,
image_bytes: bytes,
extend_left: int = 0,
extend_right: int = 0,
extend_top: int = 0,
extend_bottom: int = 0,
prompt: str = "seamless continuation of the scene",
steps: int = 40
) -> bytes:
original = Image.open(io.BytesIO(image_bytes)).convert("RGB")
orig_w, orig_h = original.size
# Новый размер холста
new_w = orig_w + extend_left + extend_right
new_h = orig_h + extend_top + extend_bottom
# Выравниваем до кратного 8
new_w = (new_w // 8) * 8
new_h = (new_h // 8) * 8
# Создаём расширенный холст
canvas = Image.new("RGB", (new_w, new_h), (128, 128, 128))
canvas.paste(original, (extend_left, extend_top))
# Маска: белый = расширенная зона, чёрный = оригинал
mask = Image.new("L", (new_w, new_h), 255)
mask_draw_area = Image.new("L", (orig_w, orig_h), 0)
mask.paste(mask_draw_area, (extend_left, extend_top))
result = self.pipe(
prompt=prompt,
image=canvas,
mask_image=mask,
height=new_h,
width=new_w,
num_inference_steps=steps,
guidance_scale=8.0,
strength=0.99
).images[0]
buf = io.BytesIO()
result.save(buf, format="PNG")
return buf.getvalue()
Конвертация форматов
class AspectRatioConverter:
"""Конвертируем квадрат в 16:9 или 9:16 через аутпейнтинг"""
def __init__(self, outpainting_service: OutpaintingService):
self.service = outpainting_service
def square_to_landscape(self, image_bytes: bytes, prompt: str = "") -> bytes:
"""1:1 → 16:9 (добавляем по бокам)"""
img = Image.open(io.BytesIO(image_bytes))
target_w = int(img.height * 16 / 9)
extend_each = (target_w - img.width) // 2
return self.service.extend_image(
image_bytes,
extend_left=extend_each,
extend_right=extend_each,
prompt=prompt or "seamless background extension, same scene"
)
def square_to_portrait(self, image_bytes: bytes, prompt: str = "") -> bytes:
"""1:1 → 9:16 (добавляем сверху и снизу)"""
img = Image.open(io.BytesIO(image_bytes))
target_h = int(img.width * 16 / 9)
extend_each = (target_h - img.height) // 2
return self.service.extend_image(
image_bytes,
extend_top=extend_each,
extend_bottom=extend_each,
prompt=prompt or "seamless extension, matching environment"
)
Тайловый аутпейнтинг для больших расширений
def extend_large(
image_bytes: bytes,
total_extension: int,
direction: str = "right",
tile_size: int = 512,
overlap: int = 128
) -> bytes:
"""Расширяем большие области тайлами с перекрытием"""
current_image = image_bytes
steps = (total_extension - overlap) // (tile_size - overlap)
for i in range(steps):
extension = min(tile_size, total_extension - i * (tile_size - overlap))
if direction == "right":
current_image = outpainting_service.extend_image(
current_image,
extend_right=extension,
prompt="seamless continuation"
)
# Аналогично для других направлений
return current_image
Применения
| Задача | Исходный формат | Целевой формат |
|---|---|---|
| Instagram → YouTube banner | 1:1 | 16:9 |
| Продуктовое фото → лендинг | 4:5 | 21:9 |
| Портрет → обложка книги | 3:4 | 2:3 с пространством для текста |
| Пейзаж → панорама | 16:9 | 32:9 |
Сроки: базовый аутпейнтинг API — 2–3 дня. Инструмент конвертации форматов с предпросмотром — 1–2 недели.







