-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Usefull for animateDiff Updates the node list
- Loading branch information
Showing
3 changed files
with
316 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,54 @@ | ||
{ | ||
"Animation Builder (mtb)": "Convenient way to manage basic animation maths at the core of many of my workflows", | ||
"Any To String (mtb)": "Tries to take any input and convert it to a string", | ||
"Bbox (mtb)": "The bounding box (BBOX) custom type used by other nodes", | ||
"Bbox From Mask (mtb)": "From a mask extract the bounding box", | ||
"Blur (mtb)": "Blur an image using a Gaussian filter.", | ||
"Color Correct (mtb)": "Various color correction methods", | ||
"Colored Image (mtb)": "Constant color image of given size", | ||
"Concat Images (mtb)": "Add images to batch", | ||
"Crop (mtb)": "Crops an image and an optional mask to a given bounding box\n\n The bounding box can be given as a tuple of (x, y, width, height) or as a BBOX type\n The BBOX input takes precedence over the tuple input\n ", | ||
"Debug (mtb)": "Experimental node to debug any Comfy values, support for more types and widgets is planned", | ||
"Deep Bump (mtb)": "Normal & height maps generation from single pictures", | ||
"Export With Ffmpeg (mtb)": "Export with FFmpeg (Experimental)", | ||
"Face Swap (mtb)": "Face swap using deepinsight/insightface models", | ||
"Film Interpolation (mtb)": "Google Research FILM frame interpolation for large motion", | ||
"Fit Number (mtb)": "Fit the input float using a source and target range", | ||
"Float To Number (mtb)": "Node addon for the WAS Suite. Converts a \"comfy\" FLOAT to a NUMBER.", | ||
"Get Batch From History (mtb)": "Very experimental node to load images from the history of the server.\n\n Queue items without output are ignored in the count.", | ||
"Image Compare (mtb)": "Compare two images and return a difference image", | ||
"Image Premultiply (mtb)": "Premultiply image with mask", | ||
"Image Remove Background Rembg (mtb)": "Removes the background from the input using Rembg.", | ||
"Image Resize Factor (mtb)": "Extracted mostly from WAS Node Suite, with a few edits (most notably multiple image support) and less features.", | ||
"Int To Bool (mtb)": "Basic int to bool conversion", | ||
"Int To Number (mtb)": "Node addon for the WAS Suite. Converts a \"comfy\" INT to a NUMBER.", | ||
"Latent Lerp (mtb)": "Linear interpolation (blend) between two latent vectors", | ||
"Load Face Analysis Model (mtb)": "Loads a face analysis model", | ||
"Load Face Enhance Model (mtb)": "Loads a GFPGan or RestoreFormer model for face enhancement.", | ||
"Load Face Swap Model (mtb)": "Loads a faceswap model", | ||
"Load Film Model (mtb)": "Loads a FILM model", | ||
"Load Image From Url (mtb)": "Load an image from the given URL", | ||
"Load Image Sequence (mtb)": "Load an image sequence from a folder. The current frame is used to determine which image to load.\n\n Usually used in conjunction with the `Primitive` node set to increment to load a sequence of images from a folder.\n Use -1 to load all matching frames as a batch.\n ", | ||
"Mask To Image (mtb)": "Converts a mask (alpha) to an RGB image with a color and background", | ||
"Qr Code (mtb)": "Basic QR Code generator", | ||
"Restore Face (mtb)": "Uses GFPGan to restore faces", | ||
"Save Gif (mtb)": "Save the images from the batch as a GIF", | ||
"Save Image Grid (mtb)": "Save all the images in the input batch as a grid of images.", | ||
"Save Image Sequence (mtb)": "Save an image sequence to a folder. The current frame is used to determine which image to save.\n\n This is merely a wrapper around the `save_images` function with formatting for the output folder and filename.\n ", | ||
"Save Tensors (mtb)": "Save torch tensors (image, mask or latent) to disk, useful to debug things outside comfy", | ||
"Smart Step (mtb)": "Utils to control the steps start/stop of the KAdvancedSampler in percentage", | ||
"String Replace (mtb)": "Basic string replacement", | ||
"Styles Loader (mtb)": "Load csv files and populate a dropdown from the rows (\u00e0 la A111)", | ||
"Text To Image (mtb)": "Utils to convert text to image using a font\n\n\n The tool looks for any .ttf file in the Comfy folder hierarchy.\n ", | ||
"Transform Image (mtb)": "Save torch tensors (image, mask or latent) to disk, useful to debug things outside comfy\n\n\n it return a tensor representing the transformed images with the same shape as the input tensor\n ", | ||
"Uncrop (mtb)": "Uncrops an image to a given bounding box\n\n The bounding box can be given as a tuple of (x, y, width, height) or as a BBOX type\n The BBOX input takes precedence over the tuple input", | ||
"Unsplash Image (mtb)": "Unsplash Image given a keyword and a size" | ||
} | ||
{ | ||
"Animation Builder (mtb)": "Convenient way to manage basic animation maths at the core of many of my workflows", | ||
"Any To String (mtb)": "Tries to take any input and convert it to a string", | ||
"Batch Float (mtb)": "Generates a batch of float values with interpolation", | ||
"Batch Shape (mtb)": "Generates a batch of 2D shapes with optional shading (experimental)", | ||
"Batch Transform (mtb)": "Transform a batch of images using a batch of keyframes", | ||
"Bbox (mtb)": "The bounding box (BBOX) custom type used by other nodes", | ||
"Bbox From Mask (mtb)": "From a mask extract the bounding box", | ||
"Blur (mtb)": "Blur an image using a Gaussian filter.", | ||
"Color Correct (mtb)": "Various color correction methods", | ||
"Colored Image (mtb)": "Constant color image of given size", | ||
"Concat Images (mtb)": "Add images to batch", | ||
"Crop (mtb)": "Crops an image and an optional mask to a given bounding box\n\n The bounding box can be given as a tuple of (x, y, width, height) or as a BBOX type\n The BBOX input takes precedence over the tuple input\n ", | ||
"Debug (mtb)": "Experimental node to debug any Comfy values, support for more types and widgets is planned", | ||
"Deep Bump (mtb)": "Normal & height maps generation from single pictures", | ||
"Export With Ffmpeg (mtb)": "Export with FFmpeg (Experimental)", | ||
"Face Swap (mtb)": "Face swap using deepinsight/insightface models", | ||
"Film Interpolation (mtb)": "Google Research FILM frame interpolation for large motion", | ||
"Fit Number (mtb)": "Fit the input float using a source and target range", | ||
"Float To Number (mtb)": "Node addon for the WAS Suite. Converts a \"comfy\" FLOAT to a NUMBER.", | ||
"Get Batch From History (mtb)": "Very experimental node to load images from the history of the server.\n\n Queue items without output are ignored in the count.", | ||
"Image Compare (mtb)": "Compare two images and return a difference image", | ||
"Image Premultiply (mtb)": "Premultiply image with mask", | ||
"Image Remove Background Rembg (mtb)": "Removes the background from the input using Rembg.", | ||
"Image Resize Factor (mtb)": "Extracted mostly from WAS Node Suite, with a few edits (most notably multiple image support) and less features.", | ||
"Image Tile Offset (mtb)": "Mimics an old photoshop technique to check for seamless textures", | ||
"Int To Bool (mtb)": "Basic int to bool conversion", | ||
"Int To Number (mtb)": "Node addon for the WAS Suite. Converts a \"comfy\" INT to a NUMBER.", | ||
"Interpolate Clip Sequential (mtb)": null, | ||
"Latent Lerp (mtb)": "Linear interpolation (blend) between two latent vectors", | ||
"Load Face Analysis Model (mtb)": "Loads a face analysis model", | ||
"Load Face Enhance Model (mtb)": "Loads a GFPGan or RestoreFormer model for face enhancement.", | ||
"Load Face Swap Model (mtb)": "Loads a faceswap model", | ||
"Load Film Model (mtb)": "Loads a FILM model", | ||
"Load Image From Url (mtb)": "Load an image from the given URL", | ||
"Load Image Sequence (mtb)": "Load an image sequence from a folder. The current frame is used to determine which image to load.\n\n Usually used in conjunction with the `Primitive` node set to increment to load a sequence of images from a folder.\n Use -1 to load all matching frames as a batch.\n ", | ||
"Mask To Image (mtb)": "Converts a mask (alpha) to an RGB image with a color and background", | ||
"Model Patch Seamless (mtb)": "Uses the stable diffusion 'hack' to infer seamless images by setting the model layers padding mode to circular (experimental)", | ||
"Qr Code (mtb)": "Basic QR Code generator", | ||
"Restore Face (mtb)": "Uses GFPGan to restore faces", | ||
"Save Gif (mtb)": "Save the images from the batch as a GIF", | ||
"Save Image Grid (mtb)": "Save all the images in the input batch as a grid of images.", | ||
"Save Image Sequence (mtb)": "Save an image sequence to a folder. The current frame is used to determine which image to save.\n\n This is merely a wrapper around the `save_images` function with formatting for the output folder and filename.\n ", | ||
"Save Tensors (mtb)": "Save torch tensors (image, mask or latent) to disk, useful to debug things outside comfy", | ||
"Smart Step (mtb)": "Utils to control the steps start/stop of the KAdvancedSampler in percentage", | ||
"Stack Images (mtb)": "Stack the input images horizontally or vertically", | ||
"String Replace (mtb)": "Basic string replacement", | ||
"Styles Loader (mtb)": "Load csv files and populate a dropdown from the rows (\u00e0 la A111)", | ||
"Text To Image (mtb)": "Utils to convert text to image using a font\n\n\n The tool looks for any .ttf file in the Comfy folder hierarchy.\n ", | ||
"Transform Image (mtb)": "Save torch tensors (image, mask or latent) to disk, useful to debug things outside comfy\n\n\n it return a tensor representing the transformed images with the same shape as the input tensor\n ", | ||
"Uncrop (mtb)": "Uncrops an image to a given bounding box\n\n The bounding box can be given as a tuple of (x, y, width, height) or as a BBOX type\n The BBOX input takes precedence over the tuple input", | ||
"Unsplash Image (mtb)": "Unsplash Image given a keyword and a size", | ||
"Vae Decode (mtb)": "Wrapper for the 2 core decoders but also adding the sd seamless hack, taken from: FlyingFireCo/tiled_ksampler" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,260 @@ | ||
import os | ||
from pathlib import Path | ||
from typing import List | ||
|
||
import cv2 | ||
import folder_paths | ||
import numpy as np | ||
import torch | ||
|
||
from ..utils import apply_easing, pil2tensor | ||
from .transform import TransformImage | ||
|
||
|
||
def hex_to_rgb(hex_color, bgr=False): | ||
hex_color = hex_color.lstrip("#") | ||
if bgr: | ||
return tuple(int(hex_color[i : i + 2], 16) for i in (4, 2, 0)) | ||
|
||
return tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4)) | ||
|
||
|
||
class BatchShape: | ||
"""Generates a batch of 2D shapes with optional shading (experimental)""" | ||
|
||
@classmethod | ||
def INPUT_TYPES(cls): | ||
return { | ||
"required": { | ||
"count": ("INT", {"default": 1}), | ||
"shape": ( | ||
["Box", "Circle", "Diamond"], | ||
{"default": "Box"}, | ||
), | ||
"image_width": ("INT", {"default": 512}), | ||
"image_height": ("INT", {"default": 512}), | ||
"shape_size": ("INT", {"default": 100}), | ||
"color": ("COLOR", {"default": "#ffffff"}), | ||
"bg_color": ("COLOR", {"default": "#000000"}), | ||
"shade_color": ("COLOR", {"default": "#000000"}), | ||
"shadex": ("FLOAT", {"default": 0.0}), | ||
"shadey": ("FLOAT", {"default": 0.0}), | ||
}, | ||
} | ||
|
||
RETURN_TYPES = ("IMAGE",) | ||
FUNCTION = "generate_shapes" | ||
CATEGORY = "mtb/batch" | ||
|
||
def generate_shapes( | ||
self, | ||
count, | ||
shape, | ||
image_width, | ||
image_height, | ||
shape_size, | ||
color, | ||
bg_color, | ||
shade_color, | ||
shadex, | ||
shadey, | ||
): | ||
print(f"COLOR: {color}") | ||
print(f"BG_COLOR: {bg_color}") | ||
print(f"SHADE_COLOR: {shade_color}") | ||
|
||
# Parse color input to BGR tuple for OpenCV | ||
color = hex_to_rgb(color) | ||
bg_color = hex_to_rgb(bg_color) | ||
shade_color = hex_to_rgb(shade_color) | ||
res = [] | ||
for x in range(count): | ||
# Initialize an image canvas | ||
canvas = np.full((image_height, image_width, 3), bg_color, dtype=np.uint8) | ||
mask = np.zeros((image_height, image_width), dtype=np.uint8) | ||
|
||
# Compute the center point of the shape | ||
center = (image_width // 2, image_height // 2) | ||
|
||
if shape == "Box": | ||
half_size = shape_size // 2 | ||
top_left = (center[0] - half_size, center[1] - half_size) | ||
bottom_right = (center[0] + half_size, center[1] + half_size) | ||
cv2.rectangle(mask, top_left, bottom_right, 255, -1) | ||
elif shape == "Circle": | ||
cv2.circle(mask, center, shape_size // 2, 255, -1) | ||
elif shape == "Diamond": | ||
pts = np.array( | ||
[ | ||
[center[0], center[1] - shape_size // 2], | ||
[center[0] + shape_size // 2, center[1]], | ||
[center[0], center[1] + shape_size // 2], | ||
[center[0] - shape_size // 2, center[1]], | ||
] | ||
) | ||
cv2.fillPoly(mask, [pts], 255) | ||
|
||
# Color the shape | ||
canvas[mask == 255] = color | ||
|
||
# Apply shading effects to a separate shading canvas | ||
shading = np.zeros_like(canvas, dtype=np.float32) | ||
shading[:, :, 0] = shadex * np.linspace(0, 1, image_width) | ||
shading[:, :, 1] = shadey * np.linspace(0, 1, image_height).reshape(-1, 1) | ||
shading_canvas = cv2.addWeighted( | ||
canvas.astype(np.float32), 1, shading, 1, 0 | ||
).astype(np.uint8) | ||
|
||
# Apply shading only to the shape area using the mask | ||
canvas[mask == 255] = shading_canvas[mask == 255] | ||
res.append(canvas) | ||
|
||
return (pil2tensor(res),) | ||
|
||
|
||
class BatchFloat: | ||
"""Generates a batch of float values with interpolation""" | ||
|
||
@classmethod | ||
def INPUT_TYPES(cls): | ||
return { | ||
"required": { | ||
"mode": ( | ||
["Single", "Steps"], | ||
{"default": "Single"}, | ||
), | ||
"count": ("INT", {"default": 1}), | ||
"min": ("FLOAT", {"default": 0.0}), | ||
"max": ("FLOAT", {"default": 1.0}), | ||
"easing": ( | ||
[ | ||
"Linear", | ||
"Sine In", | ||
"Sine Out", | ||
"Sine In/Out", | ||
"Quart In", | ||
"Quart Out", | ||
"Quart In/Out", | ||
"Cubic In", | ||
"Cubic Out", | ||
"Cubic In/Out", | ||
"Circ In", | ||
"Circ Out", | ||
"Circ In/Out", | ||
"Back In", | ||
"Back Out", | ||
"Back In/Out", | ||
"Elastic In", | ||
"Elastic Out", | ||
"Elastic In/Out", | ||
"Bounce In", | ||
"Bounce Out", | ||
"Bounce In/Out", | ||
], | ||
{"default": "Linear"}, | ||
), | ||
} | ||
} | ||
|
||
FUNCTION = "set_floats" | ||
RETURN_TYPES = ("FLOATS",) | ||
CATEGORY = "mtb/batch" | ||
|
||
def set_floats(self, mode, count, min, max, easing): | ||
keyframes = [] | ||
if mode == "Single": | ||
keyframes = [min] * count | ||
return (keyframes,) | ||
|
||
for i in range(count): | ||
normalized_step = i / (count - 1) | ||
eased_step = apply_easing(normalized_step, easing) | ||
eased_value = min + (max - min) * eased_step | ||
keyframes.append(eased_value) | ||
|
||
return (keyframes,) | ||
|
||
|
||
class Batch2dTransform: | ||
"""Transform a batch of images using a batch of keyframes""" | ||
|
||
@classmethod | ||
def INPUT_TYPES(cls): | ||
return { | ||
"required": { | ||
"image": ("IMAGE",), | ||
"border_handling": ( | ||
["edge", "constant", "reflect", "symmetric"], | ||
{"default": "edge"}, | ||
), | ||
"constant_color": ("COLOR", {"default": "#000000"}), | ||
}, | ||
"optional": { | ||
"x": ("FLOATS",), | ||
"y": ("FLOATS",), | ||
"zoom": ("FLOATS",), | ||
"angle": ("FLOATS",), | ||
"shear": ("FLOATS",), | ||
}, | ||
} | ||
|
||
RETURN_TYPES = ("IMAGE",) | ||
FUNCTION = "transform_batch" | ||
CATEGORY = "mtb/batch" | ||
|
||
def transform_batch( | ||
self, | ||
image: torch.Tensor, | ||
border_handling, | ||
constant_color, | ||
x=None, | ||
y=None, | ||
zoom=None, | ||
angle=None, | ||
shear=None, | ||
): | ||
if not any([x, y, zoom, angle]): | ||
raise ValueError("At least one transform parameter must be provided") | ||
|
||
keyframes = {"x": [], "y": [], "zoom": [], "angle": [], "shear": []} | ||
|
||
default_vals = {"x": 0, "y": 0, "zoom": 1.0, "angle": 0, "shear": 0} | ||
|
||
if x: | ||
keyframes["x"] = x | ||
if y: | ||
keyframes["y"] = y | ||
if zoom: | ||
keyframes["zoom"] = zoom | ||
if angle: | ||
keyframes["angle"] = angle | ||
if shear: | ||
keyframes["shear"] = shear | ||
|
||
for name, values in keyframes.items(): | ||
count = len(values) | ||
if count > 0 and count != image.shape[0]: | ||
raise ValueError( | ||
f"Length of {name} values ({count}) must match number of images ({image.shape[0]})" | ||
) | ||
if count == 0: | ||
keyframes[name] = [default_vals[name]] * image.shape[0] | ||
|
||
transformer = TransformImage() | ||
res = [ | ||
transformer.transform( | ||
image[i].unsqueeze(0), | ||
keyframes["x"][i], | ||
keyframes["y"][i], | ||
keyframes["zoom"][i], | ||
keyframes["angle"][i], | ||
keyframes["shear"][i], | ||
border_handling, | ||
constant_color, | ||
)[0] | ||
for i in range(image.shape[0]) | ||
] | ||
return (torch.cat(res, dim=0),) | ||
|
||
|
||
__nodes__ = [BatchFloat, Batch2dTransform, BatchShape] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters