Update controlnet_module.py
Browse files- controlnet_module.py +113 -51
controlnet_module.py
CHANGED
|
@@ -1152,42 +1152,42 @@ class ControlNetProcessor:
|
|
| 1152 |
raw_mask_array = mask_array.copy()
|
| 1153 |
|
| 1154 |
# ============================================================
|
| 1155 |
-
# POSTPROCESSING
|
| 1156 |
# ============================================================
|
| 1157 |
-
|
| 1158 |
-
|
| 1159 |
|
| 1160 |
-
|
| 1161 |
-
|
| 1162 |
|
| 1163 |
-
|
| 1164 |
-
|
| 1165 |
|
| 1166 |
-
|
| 1167 |
-
|
| 1168 |
|
| 1169 |
-
|
| 1170 |
|
| 1171 |
-
|
| 1172 |
-
|
| 1173 |
|
| 1174 |
-
|
| 1175 |
-
|
| 1176 |
|
| 1177 |
-
|
| 1178 |
-
|
| 1179 |
-
|
| 1180 |
-
|
| 1181 |
|
| 1182 |
-
|
| 1183 |
-
|
| 1184 |
-
|
| 1185 |
-
|
| 1186 |
|
| 1187 |
-
|
| 1188 |
-
|
| 1189 |
-
|
| 1190 |
-
|
| 1191 |
|
| 1192 |
|
| 1193 |
#Speicherung der Binärmaske für Inpaint da keine Graupixel
|
|
@@ -1228,35 +1228,97 @@ class ControlNetProcessor:
|
|
| 1228 |
# Nochmal weichzeichnen
|
| 1229 |
mask_array = cv2.GaussianBlur(mask_array, (11, 11), 2.0)
|
| 1230 |
|
| 1231 |
-
|
| 1232 |
-
|
| 1233 |
-
|
| 1234 |
-
|
| 1235 |
|
| 1236 |
-
|
| 1237 |
-
|
| 1238 |
|
| 1239 |
-
|
| 1240 |
-
|
| 1241 |
|
| 1242 |
-
|
| 1243 |
-
|
| 1244 |
-
|
| 1245 |
|
| 1246 |
-
|
| 1247 |
-
|
| 1248 |
-
|
| 1249 |
-
|
| 1250 |
-
|
| 1251 |
-
|
| 1252 |
-
|
| 1253 |
-
|
| 1254 |
-
|
| 1255 |
-
|
| 1256 |
-
|
| 1257 |
-
|
| 1258 |
-
|
| 1259 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1260 |
# ============================================================
|
| 1261 |
# ABSCHLIESSENDE STATISTIK
|
| 1262 |
# ============================================================
|
|
|
|
| 1152 |
raw_mask_array = mask_array.copy()
|
| 1153 |
|
| 1154 |
# ============================================================
|
| 1155 |
+
# POSTPROCESSING unterschiedlich für Crop/Original
|
| 1156 |
# ============================================================
|
| 1157 |
+
if use_crop_strategy:
|
| 1158 |
+
print("👤 POSTPROCESSING AUF CROP-GRÖSSE")
|
| 1159 |
|
| 1160 |
+
# 1. Größte zusammenhängende Komponente finden
|
| 1161 |
+
labeled_array, num_features = ndimage.label(mask_array)
|
| 1162 |
|
| 1163 |
+
if num_features > 0:
|
| 1164 |
+
print(f" 🔍 Gefundene Komponenten: {num_features}")
|
| 1165 |
|
| 1166 |
+
sizes = ndimage.sum(mask_array, labeled_array, range(1, num_features + 1))
|
| 1167 |
+
largest_component_idx = np.argmax(sizes) + 1
|
| 1168 |
|
| 1169 |
+
print(f" 👑 Größte Komponente: Nr. {largest_component_idx} mit {sizes[largest_component_idx-1]:,} Pixel")
|
| 1170 |
|
| 1171 |
+
# NUR die größte Komponente behalten (der Kopf)
|
| 1172 |
+
mask_array = np.where(labeled_array == largest_component_idx, mask_array, 0)
|
| 1173 |
|
| 1174 |
+
# MORPHOLOGISCHE OPERATIONEN FÜR SAUBEREN KOPF
|
| 1175 |
+
print(" ⚙️ Morphologische Operationen für sauberen Kopf")
|
| 1176 |
|
| 1177 |
+
# Zuerst CLOSE, um kleine Löcher im Kopf zu füllen
|
| 1178 |
+
kernel_close = np.ones((7, 7), np.uint8)
|
| 1179 |
+
mask_array = cv2.morphologyEx(mask_array, cv2.MORPH_CLOSE, kernel_close, iterations=1)
|
| 1180 |
+
print(" • MORPH_CLOSE (7x7) - Löcher im Kopf füllen")
|
| 1181 |
|
| 1182 |
+
# Dann OPEN, um kleine Ausreißer zu entfernen
|
| 1183 |
+
kernel_open = np.ones((5, 5), np.uint8)
|
| 1184 |
+
mask_array = cv2.morphologyEx(mask_array, cv2.MORPH_OPEN, kernel_open, iterations=1)
|
| 1185 |
+
print(" • MORPH_OPEN (5x5) - Rauschen entfernen")
|
| 1186 |
|
| 1187 |
+
# LEICHTER DILATE FÜR MEHR ABDECKUNG (wichtig für Gesicht!)
|
| 1188 |
+
print(" 🔲 Leichter Dilate für natürliche Abdeckung")
|
| 1189 |
+
kernel_dilate = np.ones((5, 5), np.uint8) # Größerer Kernel für Gesicht
|
| 1190 |
+
mask_array = cv2.dilate(mask_array, kernel_dilate, iterations=1)
|
| 1191 |
|
| 1192 |
|
| 1193 |
#Speicherung der Binärmaske für Inpaint da keine Graupixel
|
|
|
|
| 1228 |
# Nochmal weichzeichnen
|
| 1229 |
mask_array = cv2.GaussianBlur(mask_array, (11, 11), 2.0)
|
| 1230 |
|
| 1231 |
+
# ============================================================
|
| 1232 |
+
# Maske und Rohmaske auf Originalgröße transformieren (nur für Crop)
|
| 1233 |
+
# ============================================================
|
| 1234 |
+
print("🔄 MASKE AUF ORIGINALGRÖSSE TRANSFORMIEREN")
|
| 1235 |
|
| 1236 |
+
# 1. Maske in Crop-Größe wird konveriert von NumPy nach PIL
|
| 1237 |
+
mask_crop_pil = Image.fromarray(mask_array).convert("L")
|
| 1238 |
|
| 1239 |
+
# Leere Maske in Originalgröße
|
| 1240 |
+
mask_original = Image.new("L", original_image.size, 0)
|
| 1241 |
|
| 1242 |
+
# Crop-Maske an richtiger Position in leerem Originalbild einfügen
|
| 1243 |
+
# da Hauptprogramm Originalgröße erwartet.
|
| 1244 |
+
mask_original.paste(mask_crop_pil, (crop_x1, crop_y1))
|
| 1245 |
|
| 1246 |
+
# 2. Rohmaske ebenfalls transformieren
|
| 1247 |
+
raw_mask_crop_pil = Image.fromarray(raw_mask_array).convert("L")
|
| 1248 |
+
raw_mask_original = Image.new("L", original_image.size, 0)
|
| 1249 |
+
raw_mask_original.paste(raw_mask_crop_pil, (crop_x1, crop_y1))
|
| 1250 |
+
|
| 1251 |
+
#Binärmaske für Inpaint auf Originalgröße bringen
|
| 1252 |
+
#konvertieren zu PIL-Image
|
| 1253 |
+
inpaint_binary_crop_pil = Image.fromarray(inpaint_binary_mask).convert("L")
|
| 1254 |
+
#Leeres schwarzes Bild in Originalgröße erstellen
|
| 1255 |
+
inpaint_binary_original = Image.new("L", original_image.size, 0)
|
| 1256 |
+
#Klebe Crop-SAM-Maske auf schwarzes Bild in Originalgröße
|
| 1257 |
+
inpaint_binary_original.paste(inpaint_binary_crop_pil, (crop_x1, crop_y1))
|
| 1258 |
+
|
| 1259 |
+
else: #keine use_crop_stategy Bild<=512
|
| 1260 |
+
print("👤 POSTPROCESSING AUF ORIGINALGRÖSSE (≤512px)")
|
| 1261 |
+
|
| 1262 |
+
# POSTPROCESSING-LOGIK FÜR ORIGINALGRÖSSE
|
| 1263 |
+
labeled_array, num_features = ndimage.label(mask_array)
|
| 1264 |
+
|
| 1265 |
+
if num_features > 0:
|
| 1266 |
+
print(f" 🔍 Gefundene Komponenten: {num_features}")
|
| 1267 |
+
sizes = ndimage.sum(mask_array, labeled_array, range(1, num_features + 1))
|
| 1268 |
+
largest_component_idx = np.argmax(sizes) + 1
|
| 1269 |
+
print(f" 👑 Größte Komponente: Nr. {largest_component_idx} mit {sizes[largest_component_idx-1]:,} Pixel")
|
| 1270 |
+
|
| 1271 |
+
mask_array = np.where(labeled_array == largest_component_idx, mask_array, 0)
|
| 1272 |
+
|
| 1273 |
+
# ANGEPASSTE Morphologische Operationen für Originalgröße
|
| 1274 |
+
kernel_close = np.ones((5, 5), np.uint8)
|
| 1275 |
+
mask_array = cv2.morphologyEx(mask_array, cv2.MORPH_CLOSE, kernel_close, iterations=1)
|
| 1276 |
+
print(" • MORPH_CLOSE (5x5) - Löcher im Kopf füllen")
|
| 1277 |
+
|
| 1278 |
+
kernel_open = np.ones((3, 3), np.uint8)
|
| 1279 |
+
mask_array = cv2.morphologyEx(mask_array, cv2.MORPH_OPEN, kernel_open, iterations=1)
|
| 1280 |
+
print(" • MORPH_OPEN (3x3) - Rauschen entfernen")
|
| 1281 |
+
|
| 1282 |
+
# Leichter Dilate für mehr Abdeckung
|
| 1283 |
+
kernel_dilate = np.ones((3, 3), np.uint8)
|
| 1284 |
+
mask_array = cv2.dilate(mask_array, kernel_dilate, iterations=1)
|
| 1285 |
+
print(" • DILATE (3x3) - Natürliche Abdeckung")
|
| 1286 |
+
|
| 1287 |
+
# Binärmaske für Inpaint speichern (vor Blur)
|
| 1288 |
+
inpaint_binary_mask = mask_array.copy()
|
| 1289 |
+
|
| 1290 |
+
# ANGEPASSTER Gaussian Blur für Originalgröße
|
| 1291 |
+
mask_array = cv2.GaussianBlur(mask_array, (11, 11), 2.0)
|
| 1292 |
+
print(" • GAUSSIAN BLUR (11x11, sigma=2.0) - Weiche Übergänge")
|
| 1293 |
+
|
| 1294 |
+
# Gamma-Korrektur
|
| 1295 |
+
mask_array_float = mask_array.astype(np.float32) / 255.0
|
| 1296 |
+
mask_array_float = np.clip(mask_array_float, 0.0, 1.0)
|
| 1297 |
+
mask_array_float = mask_array_float ** 0.8
|
| 1298 |
+
mask_array = (mask_array_float * 255).astype(np.uint8)
|
| 1299 |
+
print(" • GAMMA (0.8) - Glatte Übergänge")
|
| 1300 |
+
|
| 1301 |
+
# Finaler weicher Blur
|
| 1302 |
+
mask_array = cv2.GaussianBlur(mask_array, (7, 7), 1.0)
|
| 1303 |
+
print(" • FINALER BLUR (7x7, sigma=1.0)")
|
| 1304 |
+
|
| 1305 |
+
# Prüfe Maskendichte
|
| 1306 |
+
white_pixels = np.sum(mask_array > 128)
|
| 1307 |
+
coverage_ratio = white_pixels / heur_bbox_area if heur_bbox_area > 0 else 0
|
| 1308 |
+
print(f" 📊 Aktuelle Abdeckung: {white_pixels:,}px / {heur_bbox_area:,}px = {coverage_ratio:.1%}")
|
| 1309 |
+
|
| 1310 |
+
if coverage_ratio < 0.9:
|
| 1311 |
+
print(f" ⚠️ Maske zu dünn für Gesicht (<90%)")
|
| 1312 |
+
kernel_extra = np.ones((5, 5), np.uint8)
|
| 1313 |
+
mask_array = cv2.dilate(mask_array, kernel_extra, iterations=1)
|
| 1314 |
+
mask_array = cv2.GaussianBlur(mask_array, (7, 7), 1.5)
|
| 1315 |
+
|
| 1316 |
+
# Masken sind bereits in Originalgröße
|
| 1317 |
+
mask_original = Image.fromarray(mask_array).convert("L")
|
| 1318 |
+
raw_mask_original = Image.fromarray(raw_mask_array).convert("L")
|
| 1319 |
+
inpaint_binary_original = Image.fromarray(inpaint_binary_mask).convert("L")
|
| 1320 |
+
|
| 1321 |
+
|
| 1322 |
# ============================================================
|
| 1323 |
# ABSCHLIESSENDE STATISTIK
|
| 1324 |
# ============================================================
|