99 lines
3.7 KiB
Python
99 lines
3.7 KiB
Python
# Created By MSXYZ and Claude 3 Opus
|
||
# Memory & Performance Optimized
|
||
|
||
import torch
|
||
import torch.nn.functional as F
|
||
|
||
|
||
class VideoAdaptiveAA:
|
||
def __init__(self):
|
||
pass
|
||
|
||
@classmethod
|
||
def INPUT_TYPES(s):
|
||
return {
|
||
"required": {
|
||
"images": ("IMAGE",),
|
||
"strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1}),
|
||
"edge_threshold": ("FLOAT", {"default": 0.1, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||
"blur_radius": ("INT", {"default": 1, "min": 1, "max": 5, "step": 1}),
|
||
},
|
||
}
|
||
|
||
RETURN_TYPES = ("IMAGE",)
|
||
FUNCTION = "apply_aa"
|
||
CATEGORY = "CustomPostProcess"
|
||
|
||
def apply_aa(self, images, strength, edge_threshold, blur_radius):
|
||
# ComfyUI Image format: [B, H, W, C] -> Torch format: [B, C, H, W]
|
||
img = images.permute(0, 3, 1, 2)
|
||
|
||
# --- BUG FIX #3: Alpha kanal desteği ---
|
||
# Eğer görüntü RGBA ise (4 kanal), alpha kanalını ayır ve sadece RGB üzerinde işlem yap.
|
||
has_alpha = img.shape[1] == 4
|
||
if has_alpha:
|
||
alpha = img[:, 3:4, :, :] # Alpha kanalını ayır [B, 1, H, W]
|
||
img_rgb = img[:, :3, :, :] # Sadece RGB [B, 3, H, W]
|
||
else:
|
||
img_rgb = img
|
||
|
||
# 1. Grayscale dönüşümü (Kenar tespiti için)
|
||
grayscale = (
|
||
0.2989 * img_rgb[:, 0:1, :, :]
|
||
+ 0.5870 * img_rgb[:, 1:2, :, :]
|
||
+ 0.1140 * img_rgb[:, 2:3, :, :]
|
||
)
|
||
|
||
# 2. Sobel Filtresi ile kenar tespiti
|
||
sobel_x = torch.tensor(
|
||
[[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtype=torch.float32
|
||
).view(1, 1, 3, 3).to(img.device)
|
||
sobel_y = torch.tensor(
|
||
[[-1, -2, -1], [0, 0, 0], [1, 2, 1]], dtype=torch.float32
|
||
).view(1, 1, 3, 3).to(img.device)
|
||
|
||
edges_x = F.conv2d(grayscale, sobel_x, padding=1)
|
||
edges_y = F.conv2d(grayscale, sobel_y, padding=1)
|
||
|
||
# NaN hatalarını önlemek için epsilon ekliyoruz
|
||
edges = torch.sqrt(edges_x**2 + edges_y**2 + 1e-6)
|
||
|
||
# 3. Kenar maskesi oluşturma
|
||
mask = (edges > edge_threshold).float()
|
||
mask = mask * strength
|
||
# strength > 1 olsa bile renk patlaması olmaması için clamp
|
||
mask = torch.clamp(mask, min=0.0, max=1.0)
|
||
|
||
# 4. Bulanıklaştırma (Anti-aliasing etkisi)
|
||
# --- BUG FIX #1: Sıfır-padding yerine replicate padding kullan ---
|
||
# avg_pool2d varsayılan olarak sıfırla doldurur → kenar kararmasi!
|
||
# Çözüm: önce replicate padding, sonra padding=0 ile pool.
|
||
kernel_size = blur_radius * 2 + 1
|
||
img_padded = F.pad(img_rgb, (blur_radius, blur_radius, blur_radius, blur_radius), mode="replicate")
|
||
blurred = F.avg_pool2d(img_padded, kernel_size=kernel_size, stride=1, padding=0)
|
||
|
||
# 5. Adaptive Blending: Sadece kenarları bulanık olanla değiştir
|
||
# Formül: Orijinal * (1 - mask) + Bulanık * mask
|
||
result_rgb = img_rgb * (1.0 - mask) + blurred * mask
|
||
|
||
# --- BUG FIX #2: Çıkış değerlerini [0, 1] aralığına hapset ---
|
||
result_rgb = torch.clamp(result_rgb, min=0.0, max=1.0)
|
||
|
||
# Alpha kanalı varsa geri birleştir (alpha kanalına AA uygulanmaz)
|
||
if has_alpha:
|
||
result = torch.cat([result_rgb, alpha], dim=1)
|
||
else:
|
||
result = result_rgb
|
||
|
||
# Formatı geri çevir [B, C, H, W] -> [B, H, W, C]
|
||
result = result.permute(0, 2, 3, 1)
|
||
|
||
return (result,)
|
||
|
||
NODE_CLASS_MAPPINGS = {
|
||
"VideoAdaptiveAA": VideoAdaptiveAA
|
||
}
|
||
|
||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||
"VideoAdaptiveAA": "🚀 Video Adaptive Anti-Aliasing"
|
||
} |