Files
orion4d-ComfyUI-Image-Effects/geometric/hexagonal_pixelate_node.py
T
Bouletto 4e5b534b04 Initial release - 32 image effect nodes
Complete package with Core, Creative, Vintage, Deformation, Light Effects, and Geometric categories
2025-05-28 00:18:09 +02:00

137 lines
5.4 KiB
Python

import numpy as np
import torch
import cv2
class HexagonalPixelateNode:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image": ("IMAGE",),
"hex_size": ("INT", {"default": 20, "min": 5, "max": 100, "step": 5}),
"color_mode": (["average", "center", "dominant"], {"default": "average"}),
},
"optional": {
"spacing": ("FLOAT", {"default": 0.9, "min": 0.5, "max": 1.0, "step": 0.05}),
"rotation": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 60.0, "step": 5.0}),
"outline": ("BOOLEAN", {"default": False}),
"outline_thickness": ("INT", {"default": 1, "min": 1, "max": 3, "step": 1}),
}
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "apply_hexagonal_pixelate"
CATEGORY = "Image Effects"
def apply_hexagonal_pixelate(self, image, hex_size, color_mode,
spacing=0.9, rotation=0.0, outline=False, outline_thickness=1):
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
# Créer l'image hexagonale
result = self._create_hexagonal_pattern(img_np, hex_size, color_mode,
spacing, rotation, outline, outline_thickness)
result_tensor = torch.from_numpy(result.astype(np.float32) / 255.0).unsqueeze(0)
return (result_tensor,)
def _create_hexagonal_pattern(self, image, hex_size, color_mode, spacing, rotation, outline, thickness):
"""Créer le motif hexagonal"""
h, w, c = image.shape
result = np.zeros_like(image)
# Calculer les dimensions hexagonales
hex_height = hex_size * 2
hex_width = int(hex_size * np.sqrt(3))
# Espacement entre hexagones
effective_size = hex_size * spacing
# Rotation en radians
rot_rad = np.radians(rotation)
# Parcourir la grille hexagonale
for row in range(-1, h // int(hex_height * 0.75) + 2):
for col in range(-1, w // hex_width + 2):
# Position de l'hexagone
if row % 2 == 0:
x = col * hex_width
else:
x = col * hex_width + hex_width // 2
y = row * int(hex_height * 0.75)
# Appliquer la rotation
if rotation != 0:
center_x, center_y = w // 2, h // 2
x_rot = (x - center_x) * np.cos(rot_rad) - (y - center_y) * np.sin(rot_rad) + center_x
y_rot = (x - center_x) * np.sin(rot_rad) + (y - center_y) * np.cos(rot_rad) + center_y
x, y = int(x_rot), int(y_rot)
# Vérifier si l'hexagone est dans l'image
if -hex_size <= x <= w + hex_size and -hex_size <= y <= h + hex_size:
# Créer l'hexagone
hex_points = self._create_hexagon_points(x, y, effective_size, rotation)
# Obtenir la couleur de l'hexagone
color = self._get_hexagon_color(image, hex_points, color_mode)
# Dessiner l'hexagone
if hex_points is not None:
cv2.fillPoly(result, [hex_points], color.tolist())
# Ajouter le contour si demandé
if outline:
cv2.polylines(result, [hex_points], True, (0, 0, 0), thickness)
return result
def _create_hexagon_points(self, center_x, center_y, size, rotation):
"""Créer les points d'un hexagone"""
points = []
rot_rad = np.radians(rotation)
for i in range(6):
angle = i * np.pi / 3 + rot_rad
x = center_x + size * np.cos(angle)
y = center_y + size * np.sin(angle)
points.append([int(x), int(y)])
return np.array(points, dtype=np.int32)
def _get_hexagon_color(self, image, hex_points, mode):
"""Obtenir la couleur d'un hexagone"""
h, w, c = image.shape
# Créer un masque pour l'hexagone
mask = np.zeros((h, w), dtype=np.uint8)
cv2.fillPoly(mask, [hex_points], 255)
# Obtenir les pixels dans l'hexagone
masked_pixels = image[mask > 0]
if len(masked_pixels) == 0:
return np.array([128, 128, 128]) # Couleur par défaut
if mode == "average":
return np.mean(masked_pixels, axis=0)
elif mode == "center":
# Couleur du centre de l'hexagone
center = np.mean(hex_points, axis=0).astype(int)
if 0 <= center[0] < w and 0 <= center[1] < h:
return image[center[1], center[0]]
else:
return np.mean(masked_pixels, axis=0)
elif mode == "dominant":
# Couleur dominante (approximation)
pixels_reshaped = masked_pixels.reshape(-1, 3)
unique_colors, counts = np.unique(pixels_reshaped, axis=0, return_counts=True)
return unique_colors[np.argmax(counts)]
return np.mean(masked_pixels, axis=0)