ControlNet ile Karakter Pozisyonu Kontrol Etme
Stable Diffusion ile çalışırken en çok canımı sıkan şey, aynı karakteri farklı pozisyonlarda üretmeye çalışmaktı. “Şu kızı otururken çiz” diyorsun, sistem sana ayakta duran bir şey veriyor. Tekrar deniyorsun, bu sefer garip bir açıyla geliyor. ControlNet’i keşfedene kadar bu döngüde kaç saat harcadığımı sormayın.
ControlNet, Stable Diffusion’a iskelet ve poz bilgisi vermenin en güvenilir yolu. Ama doğru yapılandırılmadığında ya hiçbir şey değişmiyor ya da output tamamen mahvoluyor. Bu yazıda gerçekten işe yarayan konfigürasyonları, hangi modelin ne zaman kullanılacağını ve production benzeri pipeline’larda ControlNet’i nasıl entegre edeceğinizi paylaşacağım.
ControlNet Nedir ve Neden Gerekli
Temel Stable Diffusion bir prompt’tan görüntü üretir. Bu süreçte modelin “ne üreteyim” sorusuna verdiği cevap büyük ölçüde rastgeleliğe dayanır. Seed sabitleyebilirsiniz, prompt’u uzun uzun yazabilirsiniz ama karakterin kolunu tam istediğiniz açıya getirmek için onlarca deneme yapmanız gerekebilir.
ControlNet bu sorunu şöyle çözer: Görüntü üretim sürecine ek bir “koşul” katmanı ekler. Bu koşul bir iskelet haritası, kenar tespiti, derinlik haritası veya normal map olabilir. Model artık sadece “şunu üret” değil, “bunu üretirken şu yapıya uy” talimatını alıyor.
Poz kontrolü için en çok kullanılan format OpenPose‘dur. OpenPose, insan vücudunun 18 temel eklem noktasını (baş, boyun, omuzlar, dirsekler, bilekler, kalçalar, dizler, bilekler, gözler, kulaklar) tespit eder ve bu noktaları bir tel iskelet haritasına dönüştürür. Siz bu haritayı modele verdiğinizde, çıktı o iskelet yapısına uyar.
Kurulum
WebUI için ControlNet Eklentisi
AUTOMATIC1111 kullanıyorsanız, ControlNet eklentisini Extensions sekmesinden yükleyebilirsiniz. Ama manuel kurulum her zaman daha güvenilir:
cd /opt/stable-diffusion-webui/extensions
git clone https://github.com/Mikubill/sd-webui-controlnet.git
cd sd-webui-controlnet
pip install -r requirements.txt
Ardından ControlNet modellerini indirmeniz gerekiyor. Bu modeller ana Stable Diffusion checkpoint’inden bağımsız, ayrı dosyalar:
mkdir -p /opt/stable-diffusion-webui/models/ControlNet
cd /opt/stable-diffusion-webui/models/ControlNet
# OpenPose modeli - poz kontrolü için temel model
wget https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11p_sd15_openpose.pth
# Config dosyası da gerekli
wget https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11p_sd15_openpose.yaml
SD 1.5 yerine SDXL kullanıyorsanız, SDXL uyumlu ControlNet modellerine ihtiyacınız var:
# SDXL için OpenPose
wget https://huggingface.co/thibaud/controlnet-openpose-sdxl-1.0/resolve/main/OpenPoseXL2.safetensors
ComfyUI Kurulumu
ComfyUI tercih ediyorsanız, ControlNet node’ları zaten built-in geliyor. Modeli doğru dizine koymanız yeterli:
mkdir -p /opt/comfyui/models/controlnet
cd /opt/comfyui/models/controlnet
wget https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11p_sd15_openpose.pth
ComfyUI’de workflow JSON’ını komut satırından test etmek için:
python main.py --listen 0.0.0.0 --port 8188 --enable-cors-header
OpenPose Haritası Oluşturma
Poz kontrolünün kalbi burada. İki yol var: mevcut bir görselden poz çıkarmak ya da sıfırdan editor ile poz oluşturmak.
Mevcut Görselden Poz Çıkarma
Elinizdeki bir fotoğraftan iskelet çıkarmak için controlnet preprocessor’ı kullanabilirsiniz:
#!/usr/bin/env python3
# pose_extractor.py - Görselden OpenPose haritası çıkarır
import cv2
import numpy as np
from controlnet_aux import OpenposeDetector
def extract_pose(image_path: str, output_path: str) -> None:
"""
Verilen görselden OpenPose iskelet haritası çıkarır.
Args:
image_path: Kaynak görsel yolu
output_path: Çıktı harita yolu
"""
detector = OpenposeDetector.from_pretrained("lllyasviel/Annotators")
image = cv2.imread(image_path)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# Poz haritasını çıkar
pose_map = detector(image_rgb, hand_and_face=True)
# Kaydet
pose_map.save(output_path)
print(f"Poz haritası kaydedildi: {output_path}")
if __name__ == "__main__":
import sys
if len(sys.argv) != 3:
print("Kullanim: python pose_extractor.py <kaynak_gorsel> <cikti_dosyasi>")
sys.exit(1)
extract_pose(sys.argv[1], sys.argv[2])
Bağımlılıkları kurmak için:
pip install controlnet-aux opencv-python pillow
python pose_extractor.py referans_foto.jpg poz_haritasi.png
API Üzerinden Toplu Poz Çıkarma
Birden fazla görselden toplu poz çıkarmanız gerekiyorsa, WebUI’nin API’sini kullanabilirsiniz:
#!/bin/bash
# batch_pose_extract.sh - Klasördeki tüm görsellerden poz çıkarır
INPUT_DIR="./input_images"
OUTPUT_DIR="./pose_maps"
API_URL="http://localhost:7860"
mkdir -p "$OUTPUT_DIR"
for img in "$INPUT_DIR"/*.{jpg,png,jpeg}; do
[ -f "$img" ] || continue
filename=$(basename "$img" | sed 's/.[^.]*$//')
echo "İşleniyor: $img"
# Base64 encode
img_b64=$(base64 -w 0 "$img")
# API isteği
response=$(curl -s -X POST "$API_URL/controlnet/detect"
-H "Content-Type: application/json"
-d "{
"controlnet_input_images": ["$img_b64"],
"controlnet_module": "openpose_full",
"controlnet_processor_res": 512
}")
# Sonucu kaydet
echo "$response" | python3 -c "
import json, sys, base64
data = json.load(sys.stdin)
img_data = base64.b64decode(data['images'][0])
with open('$OUTPUT_DIR/${filename}_pose.png', 'wb') as f:
f.write(img_data)
print('Kaydedildi: $OUTPUT_DIR/${filename}_pose.png')
"
done
echo "Tüm işlemler tamamlandı."
ControlNet Parametrelerini Anlamak
WebUI’de ControlNet sekmesini açtığınızda çok sayıda parametre görürsünüz. Her birinin ne işe yaradığını bilmeden iyi sonuç almak zor.
Temel Parametreler
Weight (Ağırlık): ControlNet’in üretim sürecine ne kadar müdahale ettiğini belirler. 0-2 arasında değer alır. 1.0 standart değer, daha yüksek değerler poz uyumunu artırır ama kaliteyi düşürebilir. Genellikle 0.8-1.2 arasında tutun.
Starting Control Step: Üretim sürecinin hangi adımından itibaren ControlNet devreye girsin. 0.0 başlangıçtan itibaren anlamına gelir. Detayları korumak için 0.0 kullanın.
Ending Control Step: ControlNet’in kaçıncı adımda etkisini kesmesi gerektiği. 0.8-1.0 arasında tutmak genellikle yeterli. 1.0 sonuna kadar aktif demek.
Preprocessor: Girdi görseline uygulanacak ön işlem. Zaten bir poz haritanız varsa “none” seçin. Ham görsel veriyorsanız “openpose_full” kullanın.
Model: Hangi ControlNet modelinin kullanılacağı. Preprocessor ile uyumlu olmalı.
Control Mode: Üç seçenek var:
- Balanced: ControlNet ve prompt eşit ağırlıkta
- My prompt is more important: Prompt öncelikli, poz ikincil
- ControlNet is more important: Poz öncelikli, prompt ikincil
Karakter pozisyonu için çoğu durumda “ControlNet is more important” veya “Balanced” kullanın.
Resize Mode: Poz haritası ile çıktı boyutu farklıysa nasıl ölçeklensin:
- Just Resize: Direkt ölçekle
- Crop and Resize: Kırp ve ölçekle
- Resize and Fill: Ölçekle ve doldur
API ile ControlNet Kullanımı
Otomatik pipeline’larda ControlNet’i kullanmak için API’yi Python ile yönetmek en esnek yol:
#!/usr/bin/env python3
# controlnet_generate.py
import requests
import base64
import json
from pathlib import Path
def load_image_as_b64(image_path: str) -> str:
"""Görsel dosyasını base64 stringine çevirir."""
with open(image_path, "rb") as f:
return base64.b64encode(f.read()).decode("utf-8")
def generate_with_pose(
prompt: str,
pose_image_path: str,
output_path: str,
negative_prompt: str = "bad anatomy, wrong anatomy, extra limb, missing limb",
width: int = 512,
height: int = 768,
steps: int = 28,
cfg_scale: float = 7.0,
controlnet_weight: float = 1.0,
api_url: str = "http://localhost:7860"
) -> None:
"""
Poz haritası kullanarak karakter görüntüsü üretir.
Args:
prompt: Pozitif prompt
pose_image_path: OpenPose harita dosya yolu
output_path: Çıktı dosya yolu
negative_prompt: Negatif prompt
width: Çıktı genişliği
height: Çıktı yüksekliği
steps: Sampling adım sayısı
cfg_scale: CFG ölçeği
controlnet_weight: ControlNet ağırlığı
api_url: WebUI API adresi
"""
pose_b64 = load_image_as_b64(pose_image_path)
payload = {
"prompt": prompt,
"negative_prompt": negative_prompt,
"width": width,
"height": height,
"steps": steps,
"cfg_scale": cfg_scale,
"sampler_name": "DPM++ 2M Karras",
"alwayson_scripts": {
"controlnet": {
"args": [
{
"enabled": True,
"image": pose_b64,
"module": "none",
"model": "control_v11p_sd15_openpose [cab727d4]",
"weight": controlnet_weight,
"starting_control_step": 0.0,
"ending_control_step": 1.0,
"control_mode": 0,
"resize_mode": 1,
"pixel_perfect": True
}
]
}
}
}
response = requests.post(
f"{api_url}/sdapi/v1/txt2img",
json=payload,
timeout=120
)
if response.status_code != 200:
raise RuntimeError(f"API hatası: {response.status_code} - {response.text}")
result = response.json()
image_data = base64.b64decode(result["images"][0])
output_file = Path(output_path)
output_file.parent.mkdir(parents=True, exist_ok=True)
with open(output_file, "wb") as f:
f.write(image_data)
print(f"Görüntü üretildi: {output_path}")
if __name__ == "__main__":
generate_with_pose(
prompt="a young woman sitting on a wooden chair, casual clothing, natural lighting, photorealistic",
pose_image_path="./pose_maps/sitting_pose.png",
output_path="./output/character_sitting.png",
controlnet_weight=1.0
)
Gerçek Dünya Senaryosu: Ürün Kataloğu için Karakter Serileri
Diyelim ki bir e-ticaret projesi için aynı karakteri 10 farklı pozisyonda üretmeniz gerekiyor. Bunu elle tek tek yapmak yerine otomatize edin:
#!/usr/bin/env python3
# character_series.py - Karakter serisi üretimi
import json
from pathlib import Path
from controlnet_generate import generate_with_pose
# Poz konfigürasyonları
POSE_CONFIGS = [
{
"name": "standing_front",
"pose_file": "poses/standing_front.png",
"prompt_suffix": "standing facing forward, arms at sides"
},
{
"name": "sitting_casual",
"pose_file": "poses/sitting_chair.png",
"prompt_suffix": "sitting on chair, relaxed posture, legs crossed"
},
{
"name": "walking",
"pose_file": "poses/walking.png",
"prompt_suffix": "walking forward, natural stride"
},
{
"name": "arms_raised",
"pose_file": "poses/arms_up.png",
"prompt_suffix": "arms raised above head, joyful expression"
}
]
BASE_PROMPT = "professional model, white background, full body shot, studio lighting, high quality, 8k"
BASE_NEGATIVE = "bad anatomy, deformed, blurry, low quality, extra limbs, missing limbs, watermark"
OUTPUT_DIR = Path("./output/character_series")
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
for config in POSE_CONFIGS:
pose_path = Path(config["pose_file"])
if not pose_path.exists():
print(f"Uyarı: Poz dosyası bulunamadı: {pose_path}, atlanıyor.")
continue
full_prompt = f"{BASE_PROMPT}, {config['prompt_suffix']}"
output_file = OUTPUT_DIR / f"{config['name']}.png"
print(f"Üretiliyor: {config['name']}")
try:
generate_with_pose(
prompt=full_prompt,
pose_image_path=str(pose_path),
output_path=str(output_file),
negative_prompt=BASE_NEGATIVE,
width=512,
height=768,
controlnet_weight=1.1
)
except Exception as e:
print(f"Hata: {config['name']} üretilemedi: {e}")
print("Seri tamamlandı.")
Bu script’i cron ile çalıştırabilir ya da bir web hook’a bağlayabilirsiniz.
Sorun Giderme
Poz Uyumu Zayıf
Üretilen görüntü poz haritasına uymuyorsa:
- ControlNet weight değerini 1.2-1.5’e çıkarın
- Control Mode’u “ControlNet is more important” yapın
- Preprocessor’ı “openpose_full” yerine “openpose” deneyin, bazen daha stabil sonuç verir
- Poz haritasının çözünürlüğünün çıktıyla aynı aspect ratio’da olduğundan emin olun
Görüntü Kalitesi Düşüyor
Yüksek weight değerlerinde kalite düşüşü görülüyorsa:
- Ending Control Step’i 0.8’e çekin, model son adımlarda serbest bıraksın
- Starting Control Step’i 0.1-0.2 yapın, ilk birkaç adımda genel kompozisyon oluşsun
- CFG Scale değerini biraz düşürün (7.0’dan 6.0’a)
“Model not found” Hatası
# Mevcut ControlNet modellerini listele
ls -la /opt/stable-diffusion-webui/models/ControlNet/
# Model hash'ini kontrol et - API'de model adı hash içermeli
curl -s http://localhost:7860/controlnet/model_list | python3 -m json.tool
API payload’ındaki model adını bu listeden aldığınız gerçek isimle eşleştirin.
Bellek Sorunları
8GB VRAM’de birden fazla ControlNet birleştirince OOM hatası alabilirsiniz:
# WebUI'yi düşük VRAM modunda başlat
python launch.py --medvram --opt-split-attention
# Veya çok düşük VRAM için
python launch.py --lowvram --opt-split-attention-v1
Birden Fazla ControlNet Kullanmak
Sadece poz değil, aynı anda derinlik haritası veya kenar tespiti de ekleyebilirsiniz. Bu, hem pozisyon hem de genel kompozisyonu kontrol etmenizi sağlar:
# Çoklu ControlNet payload örneği
"alwayson_scripts": {
"controlnet": {
"args": [
{
# Birinci: Poz kontrolü
"enabled": True,
"image": pose_map_b64,
"module": "none",
"model": "control_v11p_sd15_openpose [cab727d4]",
"weight": 1.0,
"starting_control_step": 0.0,
"ending_control_step": 1.0
},
{
# İkinci: Derinlik kontrolü
"enabled": True,
"image": depth_map_b64,
"module": "none",
"model": "control_v11f1p_sd15_depth [cfd03158]",
"weight": 0.6,
"starting_control_step": 0.0,
"ending_control_step": 0.8
}
]
}
}
Burada dikkat edilecek nokta: iki ControlNet birlikte çalışırken weight değerlerinin toplamı genellikle 2.0’ı geçmemeli. Yoksa model çelişkili sinyallerle boğuşur ve çıktı bozulur.
Sonuç
ControlNet ile poz kontrolü, doğru parametreler ve net bir workflow olmadan gerçekten sinir bozucu olabiliyor. Ama bir kez çalışan bir pipeline kurduğunuzda, aynı karakteri onlarca farklı pozisyonda tutarlı biçimde üretmek mümkün hale geliyor.
Pratikte en çok işe yarayan yaklaşım şu: Referans fotoğraflardan poz haritalarını toplu çıkarın, bunları bir kütüphanede saklayın, ardından karakter üretimini API üzerinden script haline getirin. Böylece hem tekrar kullanılabilirlik hem de kalite tutarlılığı sağlanıyor.
Weight değerleri için başlangıç noktanız 1.0 olsun, control step aralığı için 0.0-1.0. Sorun çıktıkça bu değerleri ince ayar yapın. Her model, her checkpoint farklı davranabiliyor; bu yüzden kendi notlarınızı tutun ve hangi ayarların hangi durumda işe yaradığını kaydedin.
Son olarak, poz haritalarını sıfırdan çizmek yerine mevcut fotoğraflardan çıkarmak çok daha hızlı ve güvenilir sonuç veriyor. İnternetteki stok fotoğraflar bu iş için biçilmiş kaftan, referans kütüphanenizi onlarla oluşturmaya bakın.
