diff --git a/__init__.py b/__init__.py index aa2be2a..5c868e4 100644 --- a/__init__.py +++ b/__init__.py @@ -146,6 +146,7 @@ from .nodes.images.flex_images import ( FlexImagePixelate, FlexImageColorGrade, FlexImageTiltShift, + FlexImageParallax, ) from .nodes.flex.feature_externals import ( @@ -254,7 +255,7 @@ NODE_CLASS_MAPPINGS = { "FlexImagePixelate": FlexImagePixelate, "FlexImageColorGrade": FlexImageColorGrade, "FlexImageTiltShift": FlexImageTiltShift, - + "FlexImageParallax": FlexImageParallax, #opacity xp # "FlexDepthBasedMaskOpacity": FlexDepthBasedMaskOpacity, diff --git a/node_configs.py b/node_configs.py index 963229d..9881603 100644 --- a/node_configs.py +++ b/node_configs.py @@ -800,85 +800,131 @@ NODE_CONFIGS["FlexImageBase"] = { - `feature_pipe`: Feature pipe containing frame information (FEATURE_PIPE type) - `strength`: Overall strength of the effect (0.0 to 1.0) - `feature_threshold`: Minimum feature value to apply the effect (0.0 to 1.0) -- `feature_param`: Parameter to be modulated by the feature - `feature_mode`: How the feature modulates the parameter ("relative" or "absolute"). Relative mode adjusts the parameter based on its current value, while absolute mode directly sets the parameter to the feature value. """ } +add_node_config("FlexImageEdgeDetect", { + "TOP_DESCRIPTION": "Applies edge detection to the image using the Canny algorithm.", + "ADDITIONAL_INFO": """ +- `low_threshold`: Lower bound for the hysteresis thresholding (0 to 255). +- `high_threshold`: Upper bound for the hysteresis thresholding (0 to 255). +- `feature_param`: Parameter to modulate based on the feature. Options are "low_threshold", "high_threshold", "None". + +This node detects edges in the image using the Canny edge detection algorithm. The thresholds control the sensitivity of the edge detection. +""" +}) + add_node_config("FlexImagePosterize", { "TOP_DESCRIPTION": "Applies a posterization effect to the image, reducing the number of colors.", "ADDITIONAL_INFO": """ -- `max_levels`: Maximum number of color levels per channel (2 to 256) -- `dither_strength`: Intensity of dithering effect (0.0 to 1.0) -- `channel_separation`: Degree of separation between color channels (0.0 to 1.0) -- `gamma`: Gamma correction applied before posterization (0.1 to 2.2) +- `max_levels`: Maximum number of color levels per channel (2 to 256). +- `dither_strength`: Intensity of dithering effect (0.0 to 1.0). +- `channel_separation`: Degree of separation between color channels (0.0 to 1.0). +- `gamma`: Gamma correction applied before posterization (0.1 to 2.2). +- `feature_param`: Parameter to modulate based on the feature. Options are "max_levels", "dither_strength", "channel_separation", "gamma", "None". + +This node reduces the number of colors in the image, creating a posterized effect. Dithering can be applied to reduce banding. """ }) add_node_config("FlexImageKaleidoscope", { "TOP_DESCRIPTION": "Creates a kaleidoscope effect by mirroring and rotating segments of the image.", "ADDITIONAL_INFO": """ -- `segments`: Number of mirror segments (2 to 32) -- `center_x`: X-coordinate of the effect center (0.0 to 1.0) -- `center_y`: Y-coordinate of the effect center (0.0 to 1.0) -- `zoom`: Zoom factor for the effect (0.1 to 2.0) -- `rotation`: Rotation angle of the effect (0.0 to 360.0 degrees) -- `precession`: Rate of rotation change over time (-1.0 to 1.0) -- `speed`: Speed of the effect animation (0.1 to 5.0) +- `segments`: Number of mirror segments (2 to 32). +- `center_x`: X-coordinate of the effect center (0.0 to 1.0). +- `center_y`: Y-coordinate of the effect center (0.0 to 1.0). +- `zoom`: Zoom factor for the effect (0.1 to 2.0). +- `rotation`: Rotation angle of the effect (0.0 to 360.0 degrees). +- `precession`: Rate of rotation change over time (-1.0 to 1.0). +- `speed`: Speed of the effect animation (0.1 to 5.0). +- `feature_param`: Parameter to modulate based on the feature. Options are "segments", "zoom", "rotation", "precession", "speed", "None". + +This node creates a kaleidoscope effect by mirroring and rotating segments of the image. """ }) add_node_config("FlexImageColorGrade", { "TOP_DESCRIPTION": "Applies color grading to the image using a Look-Up Table (LUT).", "ADDITIONAL_INFO": """ -- `intensity`: Strength of the color grading effect (0.0 to 1.0) -- `mix`: Blend factor between original and graded image (0.0 to 1.0) -- `lut_file`: Path to the LUT file (optional) +- `intensity`: Strength of the color grading effect (0.0 to 1.0). +- `mix`: Blend factor between original and graded image (0.0 to 1.0). +- `lut_file`: Path to the LUT file (optional). +- `feature_param`: Parameter to modulate based on the feature. Options are "intensity", "mix", "None". + +This node applies color grading to the image using a LUT. The intensity and mix parameters control the strength and blend of the effect. """ }) add_node_config("FlexImageGlitch", { "TOP_DESCRIPTION": "Creates a glitch effect by applying horizontal shifts and color channel separation.", "ADDITIONAL_INFO": """ -- `shift_amount`: Magnitude of horizontal shift (0.0 to 1.0) -- `scan_lines`: Number of scan lines to add (0 to 100) -- `color_shift`: Amount of color channel separation (0.0 to 1.0) +- `shift_amount`: Magnitude of horizontal shift (0.0 to 1.0). +- `scan_lines`: Number of scan lines to add (0 to 100). +- `color_shift`: Amount of color channel separation (0.0 to 1.0). +- `feature_param`: Parameter to modulate based on the feature. Options are "shift_amount", "scan_lines", "color_shift", "None". + +This node creates a glitch effect by shifting pixels horizontally and separating color channels. """ }) add_node_config("FlexImageChromaticAberration", { "TOP_DESCRIPTION": "Simulates chromatic aberration by shifting color channels.", "ADDITIONAL_INFO": """ -- `shift_amount`: Magnitude of color channel shift (0.0 to 0.1) -- `angle`: Angle of the shift effect (0.0 to 360.0 degrees) +- `shift_amount`: Magnitude of color channel shift (0.0 to 0.1). +- `angle`: Angle of the shift effect (0.0 to 360.0 degrees). +- `feature_param`: Parameter to modulate based on the feature. Options are "shift_amount", "angle", "None". + +This node simulates chromatic aberration by shifting the red and blue color channels in opposite directions. """ }) add_node_config("FlexImagePixelate", { "TOP_DESCRIPTION": "Applies a pixelation effect to the image.", "ADDITIONAL_INFO": """ -- `pixel_size`: Size of each pixelated block (1 to 100 pixels) +- `pixel_size`: Size of each pixelated block (1 to 100 pixels). +- `feature_param`: Parameter to modulate based on the feature. Options are "pixel_size", "None". + +This node reduces the resolution of the image by applying a pixelation effect. """ }) add_node_config("FlexImageBloom", { "TOP_DESCRIPTION": "Adds a bloom effect to bright areas of the image.", "ADDITIONAL_INFO": """ -- `threshold`: Brightness threshold for the bloom effect (0.0 to 1.0) -- `blur_amount`: Amount of blur applied to the bloom (0.0 to 50.0) -- `intensity`: Strength of the bloom effect (0.0 to 1.0) +- `threshold`: Brightness threshold for the bloom effect (0.0 to 1.0). +- `blur_amount`: Amount of blur applied to the bloom (0.0 to 50.0). +- `intensity`: Strength of the bloom effect (0.0 to 1.0). +- `feature_param`: Parameter to modulate based on the feature. Options are "threshold", "blur_amount", "intensity", "None". + +This node adds a bloom effect to bright areas of the image, creating a glowing effect. """ }) add_node_config("FlexImageTiltShift", { "TOP_DESCRIPTION": "Creates a tilt-shift effect, simulating a shallow depth of field.", "ADDITIONAL_INFO": """ -- `blur_amount`: Strength of the blur effect (0.0 to 50.0) -- `focus_position_x`: X-coordinate of the focus center (0.0 to 1.0) -- `focus_position_y`: Y-coordinate of the focus center (0.0 to 1.0) -- `focus_width`: Width of the focus area (0.0 to 1.0) -- `focus_height`: Height of the focus area (0.0 to 1.0) -- `focus_shape`: Shape of the focus area ("rectangle" or "ellipse") +- `blur_amount`: Strength of the blur effect (0.0 to 50.0). +- `focus_position_x`: X-coordinate of the focus center (0.0 to 1.0). +- `focus_position_y`: Y-coordinate of the focus center (0.0 to 1.0). +- `focus_width`: Width of the focus area (0.0 to 1.0). +- `focus_height`: Height of the focus area (0.0 to 1.0). +- `focus_shape`: Shape of the focus area ("rectangle" or "ellipse"). +- `feature_param`: Parameter to modulate based on the feature. Options are "blur_amount", "focus_position_x", "focus_position_y", "focus_width", "focus_height", "None". + +This node creates a tilt-shift effect, simulating a shallow depth of field by blurring areas outside the focus region. +""" +}) + +add_node_config("FlexImageParallax", { + "TOP_DESCRIPTION": "Applies a parallax effect to the image using a depth map.", + "ADDITIONAL_INFO": """ +- `shift_x`: Horizontal shift factor for the parallax effect (-1.0 to 1.0). Positive values shift right, negative values shift left. +- `shift_y`: Vertical shift factor for the parallax effect (-1.0 to 1.0). Positive values shift up, negative values shift down. +- `depth_map`: Input depth map (IMAGE type). The depth map is used to determine the amount of shift for each pixel. +- `feature_param`: Parameter to modulate based on the feature. Options are "shift_x", "shift_y", "None". + +This node creates a parallax effect by shifting pixels in the image based on the corresponding values in the depth map. The shift factors `shift_x` and `shift_y` control the direction and magnitude of the parallax effect. The depth map should be provided as an image, where the intensity of each pixel represents the depth value. """ }) diff --git a/nodes/images/flex_images.py b/nodes/images/flex_images.py index f2dd281..a1cbeda 100644 --- a/nodes/images/flex_images.py +++ b/nodes/images/flex_images.py @@ -258,7 +258,6 @@ class FlexImageChromaticAberration(FlexImageBase): return np.clip(result, 0, 1) - class FlexImagePixelate(FlexImageBase): @classmethod def INPUT_TYPES(cls): @@ -369,3 +368,36 @@ class FlexImageTiltShift(FlexImageBase): return np.clip(result, 0, 1) +class FlexImageParallax(FlexImageBase): + @classmethod + def INPUT_TYPES(cls): + return { + **super().INPUT_TYPES(), + "required": { + **super().INPUT_TYPES()["required"], + "shift_x": ("FLOAT", {"default": 0.1, "min": -1.0, "max": 1.0, "step": 0.01}), + "shift_y": ("FLOAT", {"default": 0.1, "min": -1.0, "max": 1.0, "step": 0.01}), + "depth_map": ("IMAGE",), # Assuming depth map is provided as an image + } + } + + @classmethod + def get_modifiable_params(cls): + return ["shift_x", "shift_y", "None"] + + def apply_effect_internal(self, image: np.ndarray, shift_x: float, shift_y: float, depth_map: np.ndarray, frame_index: int, **kwargs) -> np.ndarray: + h, w, _ = image.shape + + depth_map_frame = depth_map[frame_index].cpu().numpy() + depth_map_gray = np.mean(depth_map_frame, axis=-1) + depth_map_gray = depth_map_gray / np.max(depth_map_gray) + dx = (w * shift_x * depth_map_gray).astype(np.int32) + dy = (h * shift_y * depth_map_gray).astype(np.int32) + x, y = np.meshgrid(np.arange(w), np.arange(h)) + + new_x = np.clip(x + dx, 0, w - 1) + new_y = np.clip(y + dy, 0, h - 1) + + result = image[new_y, new_x] + + return np.clip(result, 0, 1) \ No newline at end of file diff --git a/nodes/images/image_base.py b/nodes/images/image_base.py index 0c08051..1897d90 100644 --- a/nodes/images/image_base.py +++ b/nodes/images/image_base.py @@ -59,7 +59,7 @@ class FlexImageBase(RyanOnTheInside, ABC): for i in range(num_frames): image = images_np[i] feature_value = feature.get_value_at_frame(i) - + kwargs['frame_index'] = i if feature_value >= feature_threshold: processed_image = self.process_image(image, feature_value, strength, feature_param=feature_param, diff --git a/nodes/masks/flex_masks.py b/nodes/masks/flex_masks.py index 5857788..d252ce8 100644 --- a/nodes/masks/flex_masks.py +++ b/nodes/masks/flex_masks.py @@ -9,6 +9,9 @@ from .mask_base import FlexMaskBase from scipy.ndimage import distance_transform_edt from .mask_base import FlexMaskBase from .shape_utils import create_shape_mask, get_available_shapes +import torch +from typing import List +import torch.nn.functional as F class FlexMaskMorph(FlexMaskBase): @classmethod @@ -592,7 +595,6 @@ class FlexMaskRandomShapes(FlexMaskBase): shape_type=shape_type, feature_param=feature_param, **kwargs),) -import torch class FlexMaskDepthChamber(FlexMaskBase): @classmethod def INPUT_TYPES(cls): @@ -629,11 +631,15 @@ class FlexMaskDepthChamber(FlexMaskBase): if feature_param in ["z_back", "both"]: z_back = max(0.0, z_back - (z_front - z_back) * strength * feature_value / 2) if z_back < z_front else min(1.0, z_back + (z_back - z_front) * strength * feature_value / 2) elif feature_mode == "move_forward": - z_front = min(1.0, z_front + strength * feature_value) - z_back = min(1.0, z_back + strength * feature_value) + if feature_param in ["z_front", "both"]: + z_front = min(1.0, z_front + strength * feature_value) + if feature_param in ["z_back", "both"]: + z_back = min(1.0, z_back + strength * feature_value) elif feature_mode == "move_back": - z_front = max(0.0, z_front - strength * feature_value) - z_back = max(0.0, z_back - strength * feature_value) + if feature_param in ["z_front", "both"]: + z_front = max(0.0, z_front - strength * feature_value) + if feature_param in ["z_back", "both"]: + z_back = max(0.0, z_back - strength * feature_value) # Create the depth mask if z_back < z_front: @@ -657,8 +663,6 @@ class FlexMaskDepthChamber(FlexMaskBase): feature_param=feature_param, feature_mode=feature_mode, **kwargs),) -from typing import List -import torch.nn.functional as F class FlexMaskDepthChamberRelative(FlexMaskBase): @classmethod def INPUT_TYPES(cls): diff --git a/pyproject.toml b/pyproject.toml index 2f0f71f..d4494b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "comfyui_ryanonyheinside" description = "Custom nodes introducing particle simulations, optical flow, audio manipulation & reactivity, and temporal masks" -version = "1.5.4" +version = "1.5.6" license = {file = "LICENSE"} dependencies = ["opencv-python==4.10.0","scipy","pillow","librosa","pymunk==6.8.1","matplotlib","openunmix","mido"] diff --git a/readme.md b/readme.md index dbe2a60..df50997 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ ## Overview ### RyanOnTheInside node pack introduces dynamic features to ComfyUI: - **Dynamic Reactivity**: Almost all nodes in this pack can be made to react to audio, MIDI, motion, time, color, depth, brightness, and more, allowing for incredibly dynamic and responsive workflows.** + **Dynamic Reactivity**: Almost all nodes in this pack can be made to react to audio, MIDI, motion, time, color, depth, brightness, and more, allowing for incredibly dynamic and responsive workflows. If a node prefixed with FLEX, then this reactivity is central to its functionality.** - 🎆 **Particle Systems**: Create mesmerizing, fluid-like effects - 🎵 **Audio & MIDI Processing**: Separate instruments and create audio-reactive visuals @@ -33,6 +33,7 @@ *Examples showcasing various effects using particle emitters, vortices, and other node features* ##### 🆕 Recent Updates +- 9/5/24 - **FlexImageParallax**: Add illusory depth. - 9/3/24 - **FlexMaskDepthChamber**: Mask anything within a given depth range - 9/3/24 - **FeatureFade**: another feature modifier to allow mixing of features, controled by features. Think mixing depth and motion features according to a kick drum or somthing. Ridiculous. - 9/1/24 - **Utility Nodes**: Added many utility nodes for batch manipulation and more