Skip to content

Commit 9bea181

Browse files
committed
add the ImageTransitionTopToBottom node.
1 parent 6a82f96 commit 9bea181

File tree

3 files changed

+85
-32
lines changed

3 files changed

+85
-32
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ This node is designed to generate a transition image between two images. The fir
125125
## ImageTransitionLeftToRight
126126
This node is designed to generate a transition image between two images. The first image gradually slides to the right while the second image simultaneously appears from the left, creating a smooth transition effect.
127127

128+
## ImageTransitionTopToBottom
129+
This node is designed to generate a transition image between two images. The first image gradually slides down while the second image simultaneously appears from the top, creating a smooth vertical transition effect.
130+
128131
## ImageMaskColorAverage
129132
This node is designed to calculate the average color of the image within the mask. It returns the decimal and hexadecimal values of the average color.
130133

py/nodes_video.py

Lines changed: 81 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ def adjust_frames(self, images: torch.Tensor, duration: float, fps: float, remov
5555
new_images = torch.cat([new_images, images[-1].unsqueeze(0).repeat(repeat_count, 1, 1, 1)], dim=0)
5656
return (new_images, len(new_images), fps)
5757

58-
class ImageTransitionLeftToRight:
58+
class ImageTransitionBase:
59+
"""图像过渡效果的基类"""
60+
5961
def __init__(self):
6062
pass
6163

@@ -66,6 +68,7 @@ def INPUT_TYPES(cls):
6668
"after_image": ("IMAGE",),
6769
"duration": ("FLOAT", {"default": 5.0, "min": 0.1, "max": 60.0, "step": 0.1}),
6870
"fps": ("FLOAT", {"default": 24.0, "min": 1.0, "max": 120.0, "step": 1.0}),
71+
"bounce_back": ("BOOLEAN", {"default": False}),
6972
},
7073
}
7174

@@ -74,52 +77,53 @@ def INPUT_TYPES(cls):
7477
FUNCTION = "create_transition"
7578
CATEGORY = "utils"
7679

77-
def create_transition(self, before_image: torch.Tensor, after_image: torch.Tensor, duration: float, fps: float):
78-
80+
def create_transition(self, before_image: torch.Tensor, after_image: torch.Tensor, duration: float, fps: float, bounce_back: bool = False):
7981
# 确保输入是单张图片,如果是批次则取第一张
8082
if len(before_image.shape) == 4 and before_image.shape[0] > 1:
8183
before_image = before_image[0:1]
8284
if len(after_image.shape) == 4 and after_image.shape[0] > 1:
8385
after_image = after_image[0:1]
8486

85-
# 获取目标尺寸(前图的尺寸)
86-
_, target_width = before_image.shape[1:3]
87-
88-
89-
adjusted_after = self.check_and_resizee_size(before_image, after_image)
87+
# 调整后图尺寸以匹配前图
88+
adjusted_after = self.check_and_resize_size(before_image, after_image)
9089

9190
# 计算总帧数
9291
total_frames = int(duration * fps)
9392

9493
# 创建过渡帧
9594
frames = []
9695

97-
for i in range(total_frames):
98-
# 计算当前过渡位置 (0.0 到 1.0)
99-
progress = i / (total_frames - 1) if total_frames > 1 else 1.0
100-
101-
# 计算过渡线的x坐标
102-
transition_x = int(target_width * progress)
103-
104-
# 创建新帧
105-
new_frame = torch.zeros_like(before_image)
96+
if bounce_back:
97+
# 如果启用回弹效果,先从左到右,再从右到左
98+
# 前半段:从左到右
99+
half_frames = total_frames // 2
100+
for i in range(half_frames):
101+
progress = i / (half_frames - 1) if half_frames > 1 else 1.0
102+
new_frame = self.create_transition_frame(before_image, adjusted_after, progress)
103+
frames.append(new_frame)
106104

107-
# 从左到右过渡:左侧显示后图,右侧显示前图
108-
# 先填充整个前图
109-
new_frame[0] = before_image[0]
110-
111-
# 然后在左侧填充后图(覆盖前图)
112-
if transition_x > 0:
113-
new_frame[0, :, :transition_x,:] = adjusted_after[0, :, :transition_x, :]
114-
115-
frames.append(new_frame)
105+
# 后半段:从右到左
106+
for i in range(half_frames, total_frames):
107+
progress = 1.0 - ((i - half_frames) / (total_frames - half_frames - 1) if total_frames - half_frames > 1 else 0.0)
108+
new_frame = self.create_transition_frame(before_image, adjusted_after, progress)
109+
frames.append(new_frame)
110+
else:
111+
# 正常的单向过渡
112+
for i in range(total_frames):
113+
progress = i / (total_frames - 1) if total_frames > 1 else 1.0
114+
new_frame = self.create_transition_frame(before_image, adjusted_after, progress)
115+
frames.append(new_frame)
116116

117117
# 合并所有帧
118118
result = torch.cat(frames, dim=0)
119119

120120
return (result, duration, fps)
121121

122-
def check_and_resizee_size(self, before_image, after_image):
122+
def create_transition_frame(self, before_image: torch.Tensor, after_image: torch.Tensor, progress: float):
123+
"""创建过渡帧的抽象方法,子类需要实现"""
124+
raise NotImplementedError("子类必须实现create_transition_frame方法")
125+
126+
def check_and_resize_size(self, before_image, after_image):
123127
# 获取目标尺寸(前图的尺寸)
124128
before_height, before_width = before_image.shape[1:3]
125129

@@ -130,12 +134,10 @@ def check_and_resizee_size(self, before_image, after_image):
130134
if before_height == after_height and before_width == after_width:
131135
return after_image
132136

133-
134137
# 计算宽高比
135138
before_ratio = before_width / before_height
136139
after_ratio = after_width / after_height
137140

138-
139141
logger.debug(f"before_image: {before_image.shape}, after_image: {after_image.shape}")
140142

141143
# 调整后图尺寸,填充满目标尺寸(可能需要裁剪)
@@ -168,12 +170,60 @@ def check_and_resizee_size(self, before_image, after_image):
168170

169171
return adjusted_after
170172

173+
class ImageTransitionLeftToRight(ImageTransitionBase):
174+
"""从左到右的图像过渡效果"""
175+
176+
def create_transition_frame(self, before_image: torch.Tensor, after_image: torch.Tensor, progress: float):
177+
# 获取目标尺寸(前图的尺寸)
178+
_, target_width = before_image.shape[1:3]
179+
180+
# 计算过渡线的x坐标
181+
transition_x = int(target_width * progress)
182+
183+
# 创建新帧
184+
new_frame = torch.zeros_like(before_image)
185+
186+
# 从左到右过渡:左侧显示后图,右侧显示前图
187+
# 先填充整个前图
188+
new_frame[0] = before_image[0]
189+
190+
# 然后在左侧填充后图(覆盖前图)
191+
if transition_x > 0:
192+
new_frame[0, :, :transition_x, :] = after_image[0, :, :transition_x, :]
193+
194+
return new_frame
195+
196+
class ImageTransitionTopToBottom(ImageTransitionBase):
197+
"""从上到下的图像过渡效果"""
198+
199+
def create_transition_frame(self, before_image: torch.Tensor, after_image: torch.Tensor, progress: float):
200+
# 获取目标尺寸(前图的尺寸)
201+
target_height, _ = before_image.shape[1:3]
202+
203+
# 计算过渡线的y坐标
204+
transition_y = int(target_height * progress)
205+
206+
# 创建新帧
207+
new_frame = torch.zeros_like(before_image)
208+
209+
# 从上到下过渡:上方显示后图,下方显示前图
210+
# 先填充整个前图
211+
new_frame[0] = before_image[0]
212+
213+
# 然后在上方填充后图(覆盖前图)
214+
if transition_y > 0:
215+
new_frame[0, :transition_y, :, :] = after_image[0, :transition_y, :, :]
216+
217+
return new_frame
218+
171219
NODE_CLASS_MAPPINGS = {
172220
"FrameAdjuster": FrameAdjuster,
173-
"ImageTransitionLeftToRight": ImageTransitionLeftToRight
221+
"ImageTransitionLeftToRight": ImageTransitionLeftToRight,
222+
"ImageTransitionTopToBottom": ImageTransitionTopToBottom
174223
}
175224

176225
NODE_DISPLAY_NAME_MAPPINGS = {
177226
"FrameAdjuster": "Frame Adjuster",
178-
"ImageTransitionLeftToRight": "Image Transition Left to Right"
227+
"ImageTransitionLeftToRight": "Image Transition Left to Right",
228+
"ImageTransitionTopToBottom": "Image Transition Top to Bottom"
179229
}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "comfyui-utils-nodes"
33
description = "Nodes:LoadImageWithSwitch, ImageBatchOneOrMore, ModifyTextGender, GenderControlOutput, ImageCompositeMaskedWithSwitch, ImageCompositeMaskedOneByOne, ColorCorrectOfUtils, SplitMask, MaskFastGrow, CheckpointLoaderSimpleWithSwitch, ImageResizeTo8x, MatchImageRatioToPreset, MaskFromFaceModel, MaskCoverFourCorners, DetectorForNSFW, DeepfaceAnalyzeFaceAttributes, VolcanoOutpainting, VolcanoImageEdit, etc."
4-
version = "1.3.2"
4+
version = "1.3.3"
55
license = { file = "LICENSE" }
66
dependencies = []
77

0 commit comments

Comments
 (0)