ControlNet для управління композицією зображень
ControlNet додає умови управління до Stable Diffusion: поза людини, глибина сцени, контури об'єктів, карта нормалей, сегментаційна маска. Генерація слідує заданій структурі при повній свободі стилю за промптом.
Доступні моделі 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 Depth + Canny з чертежу → фотореалістичний рендер у вказаному стилі.
Мода: OpenPose моделі → генерація одягу на заданій позі без зміни тілобудови.
Дизайн продукції: SoftEdge скетчу → кілька кольорових варіацій продукту.
Переосмислення бренду: Scribble набросок логотипу → повнокольоровий фінальний варіант.
Терміни: ControlNet API з одним типом умови — 2–3 дні. Сервіс з кількома типами та веб-інтерфейсом — 1–2 тижні.







