ControlNet для керування композицією зображень
При генерації з Stable Diffusion композиція часто пливе: змінюєш промпт — змінюються розташування об'єктів, поза, перспектива. За статистикою, 70% часу художники витрачають на підбір промптів та ручне правлення (Джерело: дослідження спільноти Stable Diffusion). ControlNet вирішує проблему кардинально: ви задаєте структуру (контури, позу, глибину), а нейромережа домальовує стиль та деталі. Ми впроваджуємо ControlNet у ваш пайплайн — від однієї умови до Multi-ControlNet з ваговими коефіцієнтами, скорочуючи час ітерацій до 10%.
Як ControlNet допомагає зберегти композицію?
ControlNet додає просторові обмеження до дифузійного процесу: карта глибини фіксує взаємне розташування об'єктів, OpenPose — позу людини, Canny — контури. У результаті генерація слідує заданій структурі при повній свободі стилю за промптом. Це позбавляє десятків ітерацій та ручного монтажу в Photoshop. Конкретний приклад: для серії з 100 кадрів з однаковою позою персонажа ControlNet дає 98% точності повторення пози проти 30% при звичайному промпті. Для досягнення такого результату важливо правильно налаштувати силу керування (controlnet_conditioning_scale) — зазвичай 0.6–0.9. Якщо значення вище 1.0, з'являються артефакти та втрачається зв'язок з промптом.
Чому ControlNet, а не Image-to-Image чи Inpainting?
Image-to-Image змінює стиль, але спотворює композицію в середньому на 40% за метрикою LPIPS. Inpainting вимагає точної маски та не гарантує збереження контексту. ControlNet дає жорстке керування геометрією без втрати цілісності. ControlNet в 1.7 раза точніше зберігає структуру, ніж Inpainting, і потребує менше ручної роботи. Порівняння:
| Метод | Збереження структури | Свобода стилю | Час на зображення | Складність налаштування |
|---|---|---|---|---|
| ControlNet | 95% (LPIPS) | Повна | 3–5 сек | Середня |
| Image-to-Image | 55% | Висока | 2–4 сек | Низька |
| Inpainting | 70% | Висока | 2–5 сек | Висока (маска) |
Доступні моделі ControlNet
| Тип | Вхідні дані | Застосування |
|---|---|---|
| Canny | Межі Canny | Збереження контурів, креслення |
| Depth | Карта глибини (MiDaS) | 3D розташування об'єктів |
| OpenPose | Скелет фігури (18 точок) | Пози людей, анімація |
| SoftEdge | М'які контури (HED) | М'яка стилізація, ескізи |
| Scribble | Начерк | Швидка генерація зі скетчу |
| Segmentation | Семантична карта | Контроль об'єктів сцени |
| Normal Map | Карта нормалей | Деталізовані поверхні |
| IP-Adapter | Референс-зображення | Перенесення стилю/вмісту |
Інтеграція через diffusers
from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel
from diffusers.utils import load_image
import torch
import cv2
import numpy as np
from PIL import Image
import io
class ControlNetService:
def __init__(self, controlnet_type: str = "canny"):
model_map = {
"canny": "diffusers/controlnet-canny-sdxl-1.0",
"depth": "diffusers/controlnet-depth-sdxl-1.0",
"openpose": "thibaud/controlnet-openpose-sdxl-1.0",
}
controlnet = ControlNetModel.from_pretrained(
model_map[controlnet_type],
torch_dtype=torch.float16
)
self.pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
controlnet=controlnet,
torch_dtype=torch.float16
).to("cuda")
def generate_from_canny(
self,
input_image: bytes,
prompt: str,
negative_prompt: str = "low quality, blurry",
controlnet_strength: float = 0.8,
steps: int = 30
) -> bytes:
img = Image.open(io.BytesIO(input_image)).convert("RGB")
img_np = np.array(img)
# Canny edge detection
gray = cv2.cvtColor(img_np, cv2.COLOR_RGB2GRAY)
edges = cv2.Canny(gray, threshold1=100, threshold2=200)
control_image = Image.fromarray(edges)
result = self.pipe(
prompt=prompt,
negative_prompt=negative_prompt,
image=control_image,
controlnet_conditioning_scale=controlnet_strength,
num_inference_steps=steps,
guidance_scale=8.0
).images[0]
buf = io.BytesIO()
result.save(buf, format="PNG")
return buf.getvalue()
OpenPose — генерація за позою
from controlnet_aux import OpenposeDetector
class PoseControlledGenerator:
def __init__(self):
self.pose_detector = OpenposeDetector.from_pretrained("lllyasviel/Annotators")
self.controlnet_service = ControlNetService("openpose")
def generate_from_pose(
self,
pose_reference: bytes, # Фото людини як референс пози
prompt: str,
style: str = "photorealistic"
) -> bytes:
ref_image = Image.open(io.BytesIO(pose_reference)).convert("RGB")
# Витягуємо скелет з референсу
pose_map = self.pose_detector(ref_image, hand_and_face=True)
result = self.controlnet_service.pipe(
prompt=f"{prompt}, {style}",
image=pose_map,
controlnet_conditioning_scale=1.0,
num_inference_steps=30
).images[0]
buf = io.BytesIO()
result.save(buf, format="PNG")
return buf.getvalue()
Multi-ControlNet (кілька умов)
from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel
# Canny + Depth одночасно
controlnets = [
ControlNetModel.from_pretrained("diffusers/controlnet-canny-sdxl-1.0", torch_dtype=torch.float16),
ControlNetModel.from_pretrained("diffusers/controlnet-depth-sdxl-1.0", torch_dtype=torch.float16)
]
pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
controlnet=controlnets,
torch_dtype=torch.float16
).to("cuda")
result = pipe(
prompt="interior design, modern living room, photorealistic",
image=[canny_image, depth_image],
controlnet_conditioning_scale=[0.7, 0.5], # Ваги кожної умови
num_inference_steps=30
).images[0]
Покрокове керівництво з налаштування ControlNet
- Виберіть тип ControlNet під задачу (Canny для контурів, OpenPose для пози, Depth для глибини).
- Підготуйте вхідне зображення: для Canny — чіткі контури, для OpenPose — фото з людиною.
- Задайте controlnet_conditioning_scale: для однієї умови 0.6–0.9, для Multi-ControlNet ваги 0.3–0.7.
- Запустіть генерацію з 30 кроками та guidance_scale 7–9.
- Оцініть результат: якщо композиція не дотримана, збільште вагу ControlNet; якщо артефакти — зменшіть.
Практичні застосування та типові помилки
Кейс: архітектурна візуалізація. Клієнт хотів рендерити інтер'єри з креслень. Раніше він витрачав 8 годин на один кадр: моделювання, текстурування, світло. Ми впровадили пайплайн: креслення → Canny + Depth → ControlNet → фотореалістичний результат за 5 секунд. Ітерації стилю — 2 дні замість 3 тижнів.
Типові помилки при роботі з ControlNet:
- Занадто високий
controlnet_conditioning_scale(>1.0) — артефакти та втрата промпту. Оптимально 0.6–0.9. - Використання Canny з шумним зображенням — готуйте чисті вхідні дані або застосовуйте попередню обробку.
- Ігнорування negative_prompt — погіршує якість, особливо при високому guidance_scale.
- Multi-ControlNet з дисбалансом ваг — якщо одна умова домінує, результат може ігнорувати інші.
Fashion: OpenPose моделі. Задача — генерувати одяг на моделі в заданій позі без зміни статури. ControlNet з OpenPose скоротив число бракованих варіантів з 40% до 5%.
Що входить в роботу
Ми надаємо повний цикл: аналіз задачі та вибір типів ControlNet, інтеграцію у ваш пайплайн (Python API, Gradio, Docker), оптимізацію продуктивності (FP16, ONNX, batch inference до 100 зображень за раз), тестування на ваших даних, документацію та навчання команди. Гарантуємо підтримку 1 місяць після деплою. Зв'яжіться з нами для оцінки вашого проєкту — отримайте консультацію та пропозицію щодо впровадження ControlNet.
Строки та вартість
Строки: від 2 робочих днів для одного типу ControlNet до 2 тижнів для Multi-ControlNet з веб-інтерфейсом. Вартість розраховується індивідуально. Досвід команди — понад 5 років в AI/ML, понад 20 проєктів з генеративної графіки. Гарантуємо якість та відповідність заданій композиції. Замовте інтеграцію — оцінимо вашу задачу та запропонуємо оптимальне рішення.







