Files
orion4d-ComfyUI-Image-Effects/geometric/polygon_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.7 KiB
Python

import numpy as np
import torch
import cv2
class PolygonNode:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image": ("IMAGE",),
"polygon_sides": ("INT", {"default": 6, "min": 3, "max": 12, "step": 1}),
"polygon_size": ("INT", {"default": 30, "min": 10, "max": 100, "step": 5}),
"reduction_factor": ("FLOAT", {"default": 0.5, "min": 0.1, "max": 0.9, "step": 0.1}),
},
"optional": {
"color_mode": (["average", "dominant", "center"], {"default": "average"}),
"edge_preservation": ("FLOAT", {"default": 0.3, "min": 0.0, "max": 1.0, "step": 0.1}),
"rotation": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 360.0, "step": 15.0}),
"outline": ("BOOLEAN", {"default": False}),
}
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "apply_polygon_reduction"
CATEGORY = "Image Effects"
def apply_polygon_reduction(self, image, polygon_sides, polygon_size, reduction_factor,
color_mode="average", edge_preservation=0.3, rotation=0.0, outline=False):
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'effet de réduction polygonale
result = self._create_polygon_reduction(img_np, polygon_sides, polygon_size,
reduction_factor, color_mode,
edge_preservation, rotation, outline)
result_tensor = torch.from_numpy(result.astype(np.float32) / 255.0).unsqueeze(0)
return (result_tensor,)
def _create_polygon_reduction(self, image, sides, size, reduction, color_mode,
edge_preservation, rotation, outline):
"""Créer l'effet de réduction polygonale"""
h, w, c = image.shape
# Calculer la nouvelle résolution
new_w = int(w * reduction)
new_h = int(h * reduction)
# Redimensionner l'image
reduced = cv2.resize(image, (new_w, new_h), interpolation=cv2.INTER_AREA)
# Créer l'image de sortie
result = np.zeros_like(image)
# Calculer l'espacement des polygones
poly_spacing_x = w / new_w
poly_spacing_y = h / new_h
# Préserver les contours si demandé
edges = None
if edge_preservation > 0:
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
edges = cv2.Canny(gray, 50, 150)
# Créer les polygones
for y in range(new_h):
for x in range(new_w):
# Position dans l'image originale
orig_x = int(x * poly_spacing_x + poly_spacing_x / 2)
orig_y = int(y * poly_spacing_y + poly_spacing_y / 2)
# Couleur du pixel réduit
pixel_color = reduced[y, x]
# Ajuster la couleur selon le mode
if color_mode == "average":
# Moyenner la région autour du pixel
region_size = max(1, int(min(poly_spacing_x, poly_spacing_y) / 2))
x1 = max(0, orig_x - region_size)
x2 = min(w, orig_x + region_size)
y1 = max(0, orig_y - region_size)
y2 = min(h, orig_y + region_size)
region = image[y1:y2, x1:x2]
if region.size > 0:
pixel_color = np.mean(region.reshape(-1, c), axis=0)
elif color_mode == "dominant":
# Couleur dominante dans la région
region_size = max(1, int(min(poly_spacing_x, poly_spacing_y) / 2))
x1 = max(0, orig_x - region_size)
x2 = min(w, orig_x + region_size)
y1 = max(0, orig_y - region_size)
y2 = min(h, orig_y + region_size)
region = image[y1:y2, x1:x2]
if region.size > 0:
pixels = region.reshape(-1, c)
unique_colors, counts = np.unique(pixels, axis=0, return_counts=True)
pixel_color = unique_colors[np.argmax(counts)]
# Créer le polygone
polygon_points = self._create_polygon_points(orig_x, orig_y, size, sides, rotation)
# Dessiner le polygone
cv2.fillPoly(result, [polygon_points], pixel_color.tolist())
# Ajouter le contour si demandé
if outline:
cv2.polylines(result, [polygon_points], True, (0, 0, 0), 1)
# Préserver les contours importants
if edge_preservation > 0 and edges is not None:
edge_mask = edges > 0
blend_factor = edge_preservation
result[edge_mask] = (result[edge_mask] * (1 - blend_factor) +
image[edge_mask] * blend_factor).astype(np.uint8)
return result
def _create_polygon_points(self, center_x, center_y, size, sides, rotation):
"""Créer les points d'un polygone"""
points = []
angle_step = 2 * np.pi / sides
rotation_rad = np.radians(rotation)
for i in range(sides):
angle = i * angle_step + rotation_rad
x = int(center_x + size * np.cos(angle))
y = int(center_y + size * np.sin(angle))
points.append([x, y])
return np.array(points, dtype=np.int32)