Complete package with Core, Creative, Vintage, Deformation, Light Effects, and Geometric categories
159 lines
5.5 KiB
Python
159 lines
5.5 KiB
Python
import numpy as np
|
|
import torch
|
|
import cv2
|
|
|
|
class HolographicNode:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE",),
|
|
"intensity": ("FLOAT", {"default": 0.6, "min": 0.0, "max": 2.0, "step": 0.1}),
|
|
"interference_lines": ("INT", {"default": 100, "min": 20, "max": 300, "step": 10}),
|
|
"color_shift": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.1}),
|
|
},
|
|
"optional": {
|
|
"chromatic_aberration": ("FLOAT", {"default": 0.3, "min": 0.0, "max": 1.0, "step": 0.05}),
|
|
"transparency": ("FLOAT", {"default": 0.7, "min": 0.1, "max": 1.0, "step": 0.05}),
|
|
"flicker": ("BOOLEAN", {"default": True}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("IMAGE",)
|
|
FUNCTION = "apply_holographic"
|
|
CATEGORY = "Image Effects"
|
|
|
|
def apply_holographic(self, image, intensity, interference_lines, color_shift,
|
|
chromatic_aberration=0.3, transparency=0.7, flicker=True):
|
|
if len(image.shape) == 4:
|
|
img_tensor = image[0]
|
|
else:
|
|
img_tensor = image
|
|
|
|
img_np = (img_tensor.cpu().numpy() * 255).astype(np.uint8)
|
|
h, w, c = img_np.shape
|
|
result = img_np.copy().astype(np.float32)
|
|
|
|
# Effet de scintillement
|
|
flicker_factor = 1.0
|
|
if flicker:
|
|
import time
|
|
flicker_factor = 0.8 + 0.2 * np.sin(time.time() * 10) * np.random.uniform(0.5, 1.0)
|
|
|
|
# Appliquer la transparence
|
|
result *= transparency
|
|
|
|
# Aberration chromatique
|
|
if chromatic_aberration > 0:
|
|
result = self._apply_chromatic_aberration(result, chromatic_aberration)
|
|
|
|
# Décalage de couleur holographique
|
|
if color_shift > 0:
|
|
result = self._apply_holographic_color_shift(result, color_shift)
|
|
|
|
# Lignes d'interférence
|
|
interference_overlay = self._create_interference_lines(h, w, interference_lines, intensity)
|
|
result += interference_overlay
|
|
|
|
# Appliquer le scintillement
|
|
result *= flicker_factor
|
|
|
|
# Normaliser
|
|
result = np.clip(result, 0, 255)
|
|
|
|
result_tensor = torch.from_numpy(result.astype(np.float32) / 255.0).unsqueeze(0)
|
|
return (result_tensor,)
|
|
|
|
def _apply_chromatic_aberration(self, image, strength):
|
|
"""Appliquer l'aberration chromatique"""
|
|
h, w = image.shape[:2]
|
|
|
|
# Séparer les canaux
|
|
r_channel = image[:, :, 0]
|
|
g_channel = image[:, :, 1]
|
|
b_channel = image[:, :, 2]
|
|
|
|
# Décalages pour chaque canal
|
|
offset = int(strength * 3)
|
|
|
|
# Décaler le rouge
|
|
M_r = np.float32([[1, 0, offset], [0, 1, 0]])
|
|
r_shifted = cv2.warpAffine(r_channel, M_r, (w, h))
|
|
|
|
# Décaler le bleu
|
|
M_b = np.float32([[1, 0, -offset], [0, 1, 0]])
|
|
b_shifted = cv2.warpAffine(b_channel, M_b, (w, h))
|
|
|
|
# Recombiner
|
|
result = np.stack([r_shifted, g_channel, b_shifted], axis=2)
|
|
return result
|
|
|
|
def _apply_holographic_color_shift(self, image, shift_strength):
|
|
"""Appliquer un décalage de couleur holographique"""
|
|
# Convertir en HSV
|
|
hsv = cv2.cvtColor(image.astype(np.uint8), cv2.COLOR_RGB2HSV).astype(np.float32)
|
|
|
|
# Créer un gradient de décalage de teinte
|
|
h, w = image.shape[:2]
|
|
y_gradient = np.linspace(0, 1, h).reshape(-1, 1)
|
|
hue_shift = y_gradient * shift_strength * 180
|
|
|
|
# Appliquer le décalage
|
|
hsv[:, :, 0] = (hsv[:, :, 0] + hue_shift) % 180
|
|
|
|
# Augmenter la saturation pour l'effet holographique
|
|
hsv[:, :, 1] = np.clip(hsv[:, :, 1] * (1 + shift_strength * 0.5), 0, 255)
|
|
|
|
# Reconvertir en RGB
|
|
result = cv2.cvtColor(hsv.astype(np.uint8), cv2.COLOR_HSV2RGB).astype(np.float32)
|
|
return result
|
|
|
|
def _create_interference_lines(self, h, w, num_lines, intensity):
|
|
"""Créer des lignes d'interférence holographiques"""
|
|
overlay = np.zeros((h, w, 3), dtype=np.float32)
|
|
|
|
# Lignes horizontales d'interférence
|
|
line_spacing = h // num_lines
|
|
|
|
for i in range(0, h, line_spacing):
|
|
# Variation d'intensité aléatoire
|
|
line_intensity = intensity * np.random.uniform(0.3, 1.0)
|
|
|
|
# Couleur arc-en-ciel basée sur la position
|
|
hue = (i / h) * 360
|
|
color = self._hsv_to_rgb(hue, 100, 100)
|
|
|
|
# Dessiner la ligne avec dégradé
|
|
line_thickness = max(1, line_spacing // 3)
|
|
for j in range(line_thickness):
|
|
if i + j < h:
|
|
alpha = 1.0 - (j / line_thickness)
|
|
overlay[i + j, :] = np.array(color) * line_intensity * alpha
|
|
|
|
return overlay
|
|
|
|
def _hsv_to_rgb(self, h, s, v):
|
|
"""Convertir HSV en RGB"""
|
|
h = h / 60.0
|
|
s = s / 100.0
|
|
v = v / 100.0
|
|
|
|
c = v * s
|
|
x = c * (1 - abs((h % 2) - 1))
|
|
m = v - c
|
|
|
|
if 0 <= h < 1:
|
|
r, g, b = c, x, 0
|
|
elif 1 <= h < 2:
|
|
r, g, b = x, c, 0
|
|
elif 2 <= h < 3:
|
|
r, g, b = 0, c, x
|
|
elif 3 <= h < 4:
|
|
r, g, b = 0, x, c
|
|
elif 4 <= h < 5:
|
|
r, g, b = x, 0, c
|
|
else:
|
|
r, g, b = c, 0, x
|
|
|
|
return ((r + m) * 255, (g + m) * 255, (b + m) * 255)
|