IPAdapter Weights¶
Documentation¶
- Class name:
IPAdapterWeights
- Category:
ipadapter/weights
- Output node:
False
The IPAdapterWeights node is designed to manage and manipulate weights within the IPAdapter framework, focusing on the application of weight strategies for image processing. It enables the customization of weight distribution across frames, supports various timing methods, and facilitates the integration of images with weight-based adjustments.
Input types¶
Required¶
weights
- A string of comma or newline-separated weight values to be converted into a list of floats. It forms the basis for weight distribution and manipulation.
- Comfy dtype:
STRING
- Python dtype:
str
timing
- Specifies the timing strategy for applying weights across frames, influencing the animation or transition effect.
- Comfy dtype:
COMBO[STRING]
- Python dtype:
str
frames
- The total number of frames to which the weights will be applied, defining the scope of the animation or transition.
- Comfy dtype:
INT
- Python dtype:
int
start_frame
- The starting frame number from which weight application begins, allowing for precise control over the animation's commencement.
- Comfy dtype:
INT
- Python dtype:
int
end_frame
- The ending frame number at which weight application concludes, marking the animation's termination point.
- Comfy dtype:
INT
- Python dtype:
int
add_starting_frames
- The number of additional frames to be added at the beginning of the animation, extending its start.
- Comfy dtype:
INT
- Python dtype:
int
add_ending_frames
- The number of additional frames to be added at the end of the animation, extending its duration.
- Comfy dtype:
INT
- Python dtype:
int
method
- The method used for applying weights across frames, affecting the pattern and distribution of weight adjustments.
- Comfy dtype:
COMBO[STRING]
- Python dtype:
str
Optional¶
image
- An optional image input that, if provided, can be used in conjunction with weights for enhanced image processing effects.
- Comfy dtype:
IMAGE
- Python dtype:
str
Output types¶
weights
- Comfy dtype:
FLOAT
- The processed list of weight values after applying the specified strategy and adjustments.
- Python dtype:
List[float]
- Comfy dtype:
weights_invert
- Comfy dtype:
FLOAT
- The inverted list of weight values, providing an alternative distribution for certain processing effects.
- Python dtype:
List[float]
- Comfy dtype:
total_frames
- Comfy dtype:
INT
- The total number of frames resulting from the applied weight strategy, including any added starting or ending frames.
- Python dtype:
int
- Comfy dtype:
image_1
- Comfy dtype:
IMAGE
- The first image output, modified according to the weight strategy and method applied.
- Python dtype:
str
- Comfy dtype:
image_2
- Comfy dtype:
IMAGE
- The second image output, modified in relation to the first image and the applied weight strategy.
- Python dtype:
str
- Comfy dtype:
weights_strategy
- Comfy dtype:
WEIGHTS_STRATEGY
- The weight strategy applied, encapsulating all weight-related parameters and their effects on the output.
- Python dtype:
Dict[str, Any]
- Comfy dtype:
Usage tips¶
- Infra type:
CPU
- Common nodes: unknown
Source code¶
class IPAdapterWeights:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"weights": ("STRING", {"default": '1.0, 0.0', "multiline": True }),
"timing": (["custom", "linear", "ease_in_out", "ease_in", "ease_out", "random"], { "default": "linear" } ),
"frames": ("INT", {"default": 0, "min": 0, "max": 9999, "step": 1 }),
"start_frame": ("INT", {"default": 0, "min": 0, "max": 9999, "step": 1 }),
"end_frame": ("INT", {"default": 9999, "min": 0, "max": 9999, "step": 1 }),
"add_starting_frames": ("INT", {"default": 0, "min": 0, "max": 9999, "step": 1 }),
"add_ending_frames": ("INT", {"default": 0, "min": 0, "max": 9999, "step": 1 }),
"method": (["full batch", "shift batches", "alternate batches"], { "default": "full batch" }),
}, "optional": {
"image": ("IMAGE",),
}
}
RETURN_TYPES = ("FLOAT", "FLOAT", "INT", "IMAGE", "IMAGE", "WEIGHTS_STRATEGY")
RETURN_NAMES = ("weights", "weights_invert", "total_frames", "image_1", "image_2", "weights_strategy")
FUNCTION = "weights"
CATEGORY = "ipadapter/weights"
def weights(self, weights='', timing='custom', frames=0, start_frame=0, end_frame=9999, add_starting_frames=0, add_ending_frames=0, method='full batch', weights_strategy=None, image=None):
import random
frame_count = image.shape[0] if image is not None else 0
if weights_strategy is not None:
weights = weights_strategy["weights"]
timing = weights_strategy["timing"]
frames = weights_strategy["frames"]
start_frame = weights_strategy["start_frame"]
end_frame = weights_strategy["end_frame"]
add_starting_frames = weights_strategy["add_starting_frames"]
add_ending_frames = weights_strategy["add_ending_frames"]
method = weights_strategy["method"]
frame_count = weights_strategy["frame_count"]
else:
weights_strategy = {
"weights": weights,
"timing": timing,
"frames": frames,
"start_frame": start_frame,
"end_frame": end_frame,
"add_starting_frames": add_starting_frames,
"add_ending_frames": add_ending_frames,
"method": method,
"frame_count": frame_count,
}
# convert the string to a list of floats separated by commas or newlines
weights = weights.replace("\n", ",")
weights = [float(weight) for weight in weights.split(",") if weight.strip() != ""]
if timing != "custom":
frames = max(frames, 2)
start = 0.0
end = 1.0
if len(weights) > 0:
start = weights[0]
end = weights[-1]
weights = []
end_frame = min(end_frame, frames)
duration = end_frame - start_frame
if start_frame > 0:
weights.extend([start] * start_frame)
for i in range(duration):
n = duration - 1
if timing == "linear":
weights.append(start + (end - start) * i / n)
elif timing == "ease_in_out":
weights.append(start + (end - start) * (1 - math.cos(i / n * math.pi)) / 2)
elif timing == "ease_in":
weights.append(start + (end - start) * math.sin(i / n * math.pi / 2))
elif timing == "ease_out":
weights.append(start + (end - start) * (1 - math.cos(i / n * math.pi / 2)))
elif timing == "random":
weights.append(random.uniform(start, end))
weights[-1] = end if timing != "random" else weights[-1]
if end_frame < frames:
weights.extend([end] * (frames - end_frame))
if len(weights) == 0:
weights = [0.0]
frames = len(weights)
# repeat the images for cross fade
image_1 = None
image_2 = None
# Calculate the min and max of the weights
min_weight = min(weights)
max_weight = max(weights)
if image is not None:
if "shift" in method:
image_1 = image[:-1]
image_2 = image[1:]
weights = weights * image_1.shape[0]
image_1 = image_1.repeat_interleave(frames, 0)
image_2 = image_2.repeat_interleave(frames, 0)
elif "alternate" in method:
image_1 = image[::2].repeat_interleave(2, 0)
image_1 = image_1[1:]
image_2 = image[1::2].repeat_interleave(2, 0)
# Invert the weights relative to their own range
mew_weights = weights + [max_weight - (w - min_weight) for w in weights]
mew_weights = mew_weights * (image_1.shape[0] // 2)
if image.shape[0] % 2:
image_1 = image_1[:-1]
else:
image_2 = image_2[:-1]
mew_weights = mew_weights + weights
weights = mew_weights
image_1 = image_1.repeat_interleave(frames, 0)
image_2 = image_2.repeat_interleave(frames, 0)
else:
weights = weights * image.shape[0]
image_1 = image.repeat_interleave(frames, 0)
# add starting and ending frames
if add_starting_frames > 0:
weights = [weights[0]] * add_starting_frames + weights
image_1 = torch.cat([image[:1].repeat(add_starting_frames, 1, 1, 1), image_1], dim=0)
if image_2 is not None:
image_2 = torch.cat([image[:1].repeat(add_starting_frames, 1, 1, 1), image_2], dim=0)
if add_ending_frames > 0:
weights = weights + [weights[-1]] * add_ending_frames
image_1 = torch.cat([image_1, image[-1:].repeat(add_ending_frames, 1, 1, 1)], dim=0)
if image_2 is not None:
image_2 = torch.cat([image_2, image[-1:].repeat(add_ending_frames, 1, 1, 1)], dim=0)
# reverse the weights array
weights_invert = weights[::-1]
frame_count = len(weights)
return (weights, weights_invert, frame_count, image_1, image_2, weights_strategy,)