Реализация Outpainting (расширение границ изображения)

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1 услугВсе 1566 услуг
Реализация Outpainting (расширение границ изображения)
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы
Направления AI-разработки
Этапы разработки AI-решения
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1218
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    853
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1047
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    825

Разработка 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 недели.