Fix Fill Nodes PR follow-up edge cases

This commit is contained in:
filliptm
2026-06-22 14:23:20 -05:00
parent f2ce4bd73c
commit 3078ffa3be
2 changed files with 54 additions and 56 deletions
+40 -42
View File
@@ -152,11 +152,10 @@ class FL_InpaintCrop:
# Erode
inverted = 1 - dilated
eroded_inv = F.conv2d(inverted, kernel, padding=0)
eroded_inv = F.conv2d(inverted, kernel, padding=padding)
closed = 1 - (eroded_inv > 0).float()
# Remove padding
closed = closed[0, 0, padding:-padding, padding:-padding]
closed = closed[0, 0]
# Fill holes (find isolated regions of 0s surrounded by 1s)
h, w = closed.shape
@@ -192,14 +191,48 @@ class FL_InpaintCrop:
if not new_seed.any():
break
# The holes are the areas that weren't reached
holes = (1 - seed) * (1 - closed)
# The holes are the areas that weren't reached
holes = (1 - seed) * (1 - closed)
# Add the holes to the original mask
filled = torch.clamp(closed + holes, 0, 1)
return filled
def normalize_mask(self, mask, target_height, target_width, label):
if mask.dim() == 2:
mask = mask.unsqueeze(0)
elif mask.dim() == 3:
if mask.shape[0] == target_height and mask.shape[1] == target_width and mask.shape[-1] == 1:
mask = mask[..., 0].unsqueeze(0)
elif mask.dim() == 4:
if mask.shape[1] == 1:
mask = mask[:, 0]
elif mask.shape[-1] == 1:
mask = mask[..., 0]
elif mask.shape[1] <= 4 and mask.shape[-1] > 4:
mask = mask.float().mean(dim=1)
elif mask.shape[-1] <= 4:
mask = mask.float().mean(dim=-1)
else:
raise ValueError(f"Unsupported {label} shape: {mask.shape}")
else:
raise ValueError(f"Unsupported {label} shape: {mask.shape}")
if mask.dim() != 3:
raise ValueError(f"Unsupported {label} shape after normalization: {mask.shape}")
mask = mask.float()
if mask.shape[-2] != target_height or mask.shape[-1] != target_width:
mask = F.interpolate(
mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])),
size=(target_height, target_width),
mode='nearest'
).squeeze(1)
print(f"[FL Inpaint Crop] Auto-resized {label} to {target_width}x{target_height}")
return torch.clamp(mask, 0.0, 1.0)
# Simplified inpaint crop - clean and predictable
def inpaint_crop(self, image, mask, context_factor, target_size, resize_mode, force_square, divisible_by, invert_mask, fill_mask_holes, use_gpu, optional_context_mask=None):
"""
@@ -218,39 +251,7 @@ class FL_InpaintCrop:
original_mask = mask
original_height, original_width = image.shape[1], image.shape[2]
# Auto-resize mask to match image size
if mask.shape[-2] != image.shape[1] or mask.shape[-1] != image.shape[2]:
# Normalize mask to NCHW
if mask.dim() == 2:
mask_nchw = mask.unsqueeze(0).unsqueeze(0)
elif mask.dim() == 3:
if mask.shape[0] == 1:
mask_nchw = mask.unsqueeze(1)
else:
mask_nchw = mask.unsqueeze(0)
elif mask.dim() == 4:
mask_nchw = mask
else:
raise ValueError(f"Unsupported mask shape: {mask.shape}")
# 🔥 nchw to float
mask_nchw = mask_nchw.float()
# Resize safely
mask_resized = F.interpolate(
mask_nchw,
size=(image.shape[1], image.shape[2]),
mode='nearest'
)
# Return to [1, H, W]
mask = mask_resized.squeeze(0).squeeze(0)
# Clamp to valid mask range
mask = torch.clamp(mask, 0.0, 1.0)
print(f"[FL Inpaint Crop] Auto-resized mask to {image.shape[2]}x{image.shape[1]}")
mask = self.normalize_mask(mask, original_height, original_width, "mask")
# Invert mask if requested
if invert_mask:
@@ -283,11 +284,8 @@ class FL_InpaintCrop:
# Determine context mask
if optional_context_mask is None:
context_mask = mask
elif optional_context_mask.shape[1] != image.shape[1] or optional_context_mask.shape[2] != image.shape[2]:
optional_context_mask = F.interpolate(optional_context_mask.unsqueeze(1), size=(image.shape[1], image.shape[2]), mode='nearest').squeeze(1)
print(f"[FL Inpaint Crop] Auto-resized context mask to {image.shape[2]}x{image.shape[1]}")
context_mask = torch.clamp(optional_context_mask + mask, 0.0, 1.0)
else:
optional_context_mask = self.normalize_mask(optional_context_mask, original_height, original_width, "context mask")
context_mask = torch.clamp(optional_context_mask + mask, 0.0, 1.0)
# Find mask bounds
+14 -14
View File
@@ -1,8 +1,6 @@
// custom_nodes/FL_SystemCheck.js
// PATCHED VERSION (DOM widget) — compatible con el frontend nuevo de ComfyUI (>= 1.x).
// Mantiene el boton "Run System Check" y el fetch a /fl_system_info, pero renderiza la
// informacion en un DOM widget en lugar del dibujo legacy con onDrawForeground (que el
// frontend nuevo ya no pinta). Original de filliptm (Machine Delusions).
// Render system info in a DOM widget so it stays visible on the current
// ComfyUI frontend instead of relying on legacy canvas foreground drawing.
import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
@@ -45,37 +43,39 @@ const colorFor = (k) => COLORS[k] || "#95a5a6";
app.registerExtension({
name: "FL.SystemCheck",
async nodeCreated(node) {
if (node.comfyClass !== "FL_SystemCheck") return;
const comfyClass = (node.constructor && node.constructor.comfyClass) || node.comfyClass || "";
if (comfyClass !== "FL_SystemCheck") return;
node.color = "#2a363b";
node.bgcolor = "#4F0074";
// Contenedor del DOM widget donde se pinta la info
const container = document.createElement("div");
container.style.cssText =
"display:flex;flex-direction:column;gap:6px;padding:6px;box-sizing:border-box;" +
"width:100%;height:100%;overflow:auto;font-family:Arial,sans-serif;font-size:12px;color:#fff;";
const placeholder = document.createElement("div");
placeholder.textContent = 'Pulsa "Run System Check".';
placeholder.textContent = 'Click "Run System Check".';
placeholder.style.opacity = "0.6";
container.appendChild(placeholder);
// Boton
node.addWidget("button", "Run System Check", null, () => runSystemCheck(node, container));
// DOM widget (esto es lo que el frontend nuevo SI renderiza)
node.addDOMWidget("fl_system_info", "div", container, { serialize: false });
node.addDOMWidget("fl_system_info", "div", container, {
getMinHeight: () => 260,
hideOnZoom: false,
serialize: false,
});
// Tamano inicial decente
node.size = [360, 340];
const [oldWidth, oldHeight] = node.size;
node.setSize([Math.max(oldWidth, 360), Math.max(oldHeight, 340)]);
},
});
async function runSystemCheck(node, container) {
container.innerHTML = "";
const loading = document.createElement("div");
loading.textContent = "Comprobando…";
loading.textContent = "Checking...";
loading.style.opacity = "0.7";
container.appendChild(loading);
@@ -90,7 +90,7 @@ async function runSystemCheck(node, container) {
container.innerHTML = "";
const err = document.createElement("div");
err.style.color = "#ff6b6b";
err.textContent = "Error: " + e.message + " (mira la consola).";
err.textContent = "Error: " + e.message + " (check the console).";
container.appendChild(err);
console.error("[FL System Check]", e);
}