From 5d8bc5294f7b4f7ad250bfdec5f38df3ab8a7eb3 Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:43:09 -0400 Subject: [PATCH] fixes, toml, readme, gitattributes updates requirements, now scale does so from center, various other updates --- .gitattributes | 1 + assets/time.gif | Bin 0 -> 48988 bytes examples/mask_examples.json | 5142 ++++++++++++++++++---------------- nodes/masks/mask_base.py | 12 +- nodes/masks/mask_utils.py | 12 +- nodes/masks/utility_nodes.py | 4 +- pyproject.toml | 25 + readme.md | 21 +- requirements.txt | 10 +- 9 files changed, 2771 insertions(+), 2456 deletions(-) create mode 100644 .gitattributes create mode 100644 assets/time.gif create mode 100644 pyproject.toml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c10c889 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +assets/* export-ignore \ No newline at end of file diff --git a/assets/time.gif b/assets/time.gif new file mode 100644 index 0000000000000000000000000000000000000000..57e1ac7351285acef62a8130aba166e0b88a4b55 GIT binary patch literal 48988 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 np.ndarray: """ @@ -208,9 +212,10 @@ class TemporalMaskBase(MaskBase, ABC): class ParticleSystemMaskBase(MaskBase, ABC): @classmethod def INPUT_TYPES(cls): + parent_inputs = super().INPUT_TYPES() return { "required": { - **super().INPUT_TYPES()["required"], + **parent_inputs["required"], "emitters": ("PARTICLE_EMITTER",), "particle_count": ("INT", {"default": 200, "min": 1, "max": 10000, "step": 1}), "particle_lifetime": ("FLOAT", {"default": 4.0, "min": 0.1, "max": 10.0, "step": 0.1}), @@ -593,6 +598,9 @@ class OpticalFlowMaskBase(MaskBase, ABC): CATEGORY = "/RyanOnTheInside/masks/" + def __init__(self): + super().__init__() + def process_mask(self, mask: np.ndarray, strength: float, images: np.ndarray, flow_method: str, flow_threshold: float, magnitude_threshold: float, frame_index: int, **kwargs) -> np.ndarray: if frame_index == 0 or frame_index >= len(images) - 1: return mask diff --git a/nodes/masks/mask_utils.py b/nodes/masks/mask_utils.py index 629dc17..e3e82af 100644 --- a/nodes/masks/mask_utils.py +++ b/nodes/masks/mask_utils.py @@ -61,12 +61,16 @@ def rotate_mask(mask: np.ndarray, angle: float) -> np.ndarray: def scale_mask(mask: np.ndarray, scale_x: float, scale_y: float) -> np.ndarray: height, width = mask.shape[:2] - M = cv2.getAffineTransform( - np.float32([[0, 0], [width, 0], [0, height]]), - np.float32([[0, 0], [width * scale_x, 0], [0, height * scale_y]]) - ) + center_x, center_y = width / 2, height / 2 + + M = np.float32([ + [scale_x, 0, center_x * (1 - scale_x)], + [0, scale_y, center_y * (1 - scale_y)] + ]) + return warp_affine(mask, M) + def transform_mask(mask: np.ndarray, transform_type: str, x_value: float, y_value: float) -> np.ndarray: if transform_type == "translate": return translate_mask(mask, x_value, y_value) diff --git a/nodes/masks/utility_nodes.py b/nodes/masks/utility_nodes.py index c87ded4..fc79d9e 100644 --- a/nodes/masks/utility_nodes.py +++ b/nodes/masks/utility_nodes.py @@ -160,8 +160,8 @@ class TextMaskNode: "font_size": ("INT", {"default": 32, "min": 1, "max": 1000}), "font_color": ("STRING", {"default": "(255,255,255)"}), "background_color": ("STRING", {"default": "(0,0,0)"}), - "x_position": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0}), - "y_position": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0}), + "x_position": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step":0.01}), + "y_position": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step":0.01}), "rotation": ("FLOAT", {"default": 0, "min": 0, "max": 360}), "max_width_ratio": ("FLOAT", {"default": 0.9, "min": 0.1, "max": 1.0}), "batch_size": ("INT", {"default": 1, "min": 1, "max": 10000}), diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..dd683e9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,25 @@ +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "ComfyUI_RyanOnTheInside" +description = "Custom nodes introducing particle simulations, optical flow, and temporal masks" +version = "0.1.0" +license = { text = "CC BY-NC 4.0" } +dependencies = [ + "opencv-python==4.10", + "scipy", + "pillow", + "librosa", + "pymunk==6.8.1", + "matplotlib" +] + +[project.urls] +Repository = "https://github.com/ryanontheinside/ComfyUI_RyanOnTheInside" + +[tool.comfy] +PublisherId = "ryanontheinside" +DisplayName = "RyanOnTheInside" +Icon = "" \ No newline at end of file diff --git a/readme.md b/readme.md index dac8a7f..061eceb 100644 --- a/readme.md +++ b/readme.md @@ -6,13 +6,18 @@ RyanOnTheInside node pack introduces the following (so far): - Optical Flow - Temporal Masks - RyanOnTheInside particle demo header + +
+ RyanOnTheInside particle demo header + RyanOnTheInside optical flow demo +
+ Time + Plume examples using two particle emitters +
+ Plume examples using two particle emitters +
- Plume examples using two particle emitters - - Plume examples using two particle emitters - - *Some examples using particle emitters and vortices* +*Some examples using particle emitters and vortices* ## Installation @@ -160,6 +165,10 @@ Motion-based effects: - Directional flow isolation and emphasis - in progress - Advanced blending and modulation options + Particle System Demo + + *Motion generated trails* + ### Optical Flow Mask Nodes #### General optical mask settings diff --git a/requirements.txt b/requirements.txt index 3c6a9a2..2f81875 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,6 @@ -opencv-python -numpy -torch -tqdm +opencv-python==4.10 scipy pillow librosa -pymunk -matplotlib -Pillow \ No newline at end of file +pymunk==6.8.1 +matplotlib \ No newline at end of file