Розробка AI-інпейнтингу для заповнення областей зображення
Інпейнтинг замінює виділену маскою область зображення новим змістом, органічно вписуючи його в оточуючий контекст. Застосовується для видалення об'єктів, заміни фонів, реставрації, змін елементів дизайну.
diffusers інпейнтинг
from diffusers import StableDiffusionXLInpaintPipeline
from PIL import Image, ImageDraw
import torch
import io
import numpy as np
class InpaintingService:
def __init__(self):
self.pipe = StableDiffusionXLInpaintPipeline.from_pretrained(
"diffusers/stable-diffusion-xl-1.0-inpainting-0.1",
torch_dtype=torch.float16,
use_safetensors=True,
variant="fp16"
).to("cuda")
def inpaint(
self,
image_bytes: bytes,
mask_bytes: bytes, # білий = замінити, чорний = зберегти
prompt: str,
negative_prompt: str = "low quality, blurry, artifacts",
strength: float = 0.99,
steps: int = 30,
guidance_scale: float = 8.0
) -> bytes:
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
mask = Image.open(io.BytesIO(mask_bytes)).convert("L")
# Розміри повинні збігатися і бути кратні 8
w, h = image.size
w, h = (w // 8) * 8, (h // 8) * 8
image = image.resize((w, h))
mask = mask.resize((w, h))
result = self.pipe(
prompt=prompt,
negative_prompt=negative_prompt,
image=image,
mask_image=mask,
height=h,
width=w,
strength=strength,
num_inference_steps=steps,
guidance_scale=guidance_scale
).images[0]
buf = io.BytesIO()
result.save(buf, format="PNG")
return buf.getvalue()
Автоматичне створення маски
from transformers import pipeline
import numpy as np
class AutoMaskGenerator:
def __init__(self):
# SAM (Segment Anything) для точної сегментації
self.sam = pipeline("mask-generation", model="facebook/sam-vit-huge", device="cuda")
def mask_by_text(self, image: Image.Image, text_query: str) -> Image.Image:
"""Створюємо маску через CLIP + SAM за текстовим описом"""
from transformers import CLIPSegProcessor, CLIPSegForImageSegmentation
processor = CLIPSegProcessor.from_pretrained("CIDAS/clipseg-rd64-refined")
seg_model = CLIPSegForImageSegmentation.from_pretrained("CIDAS/clipseg-rd64-refined")
inputs = processor(
text=[text_query],
images=[image],
return_tensors="pt"
)
outputs = seg_model(**inputs)
mask = outputs.logits.squeeze().sigmoid().detach().numpy()
# Бінаризуємо
mask_binary = (mask > 0.5).astype(np.uint8) * 255
return Image.fromarray(mask_binary).resize(image.size)
def mask_by_coords(self, image: Image.Image, bbox: tuple) -> Image.Image:
"""Маска за bounding box"""
x1, y1, x2, y2 = bbox
mask = Image.new("L", image.size, 0)
draw = ImageDraw.Draw(mask)
draw.rectangle([x1, y1, x2, y2], fill=255)
return mask
Типові сценарії
class InpaintingUseCases:
async def remove_object(self, image: bytes, object_mask: bytes) -> bytes:
"""Видаляємо об'єкт, заповнюємо фоном"""
return self.pipe.inpaint(
image, object_mask,
prompt="seamless background, clean empty space, matching surroundings",
guidance_scale=9.0
)
async def replace_background(self, image: bytes, subject_mask_inverted: bytes, new_background: str) -> bytes:
"""Змінюємо фон при утриманні суб'єкта"""
return self.pipe.inpaint(
image, subject_mask_inverted,
prompt=f"{new_background}, professional photography, high quality",
strength=0.95
)
async def change_product_color(self, product_image: bytes, product_mask: bytes, color: str) -> bytes:
"""Змінюємо колір товару для каталогу"""
return self.pipe.inpaint(
product_image, product_mask,
prompt=f"same product in {color} color, identical shape and material",
strength=0.7, # низький strength зберігає форму
guidance_scale=10.0
)
API endpoint
from fastapi import FastAPI, File, UploadFile, Form
app = FastAPI()
inpainting = InpaintingService()
@app.post("/inpaint")
async def inpaint_image(
image: UploadFile = File(...),
mask: UploadFile = File(...),
prompt: str = Form(...),
strength: float = Form(0.99)
):
image_bytes = await image.read()
mask_bytes = await mask.read()
result = inpainting.inpaint(image_bytes, mask_bytes, prompt, strength=strength)
return Response(content=result, media_type="image/png")
Терміни: базовий API інпейнтингу — 2–3 дні. Сервіс з автосегментацією за кліком/текстом та веб-інтерфейсом — 2–3 тижні.







