@@ -55,7 +55,9 @@ def adjust_frames(self, images: torch.Tensor, duration: float, fps: float, remov
55
55
new_images = torch .cat ([new_images , images [- 1 ].unsqueeze (0 ).repeat (repeat_count , 1 , 1 , 1 )], dim = 0 )
56
56
return (new_images , len (new_images ), fps )
57
57
58
- class ImageTransitionLeftToRight :
58
+ class ImageTransitionBase :
59
+ """图像过渡效果的基类"""
60
+
59
61
def __init__ (self ):
60
62
pass
61
63
@@ -66,6 +68,7 @@ def INPUT_TYPES(cls):
66
68
"after_image" : ("IMAGE" ,),
67
69
"duration" : ("FLOAT" , {"default" : 5.0 , "min" : 0.1 , "max" : 60.0 , "step" : 0.1 }),
68
70
"fps" : ("FLOAT" , {"default" : 24.0 , "min" : 1.0 , "max" : 120.0 , "step" : 1.0 }),
71
+ "bounce_back" : ("BOOLEAN" , {"default" : False }),
69
72
},
70
73
}
71
74
@@ -74,52 +77,53 @@ def INPUT_TYPES(cls):
74
77
FUNCTION = "create_transition"
75
78
CATEGORY = "utils"
76
79
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 ):
79
81
# 确保输入是单张图片,如果是批次则取第一张
80
82
if len (before_image .shape ) == 4 and before_image .shape [0 ] > 1 :
81
83
before_image = before_image [0 :1 ]
82
84
if len (after_image .shape ) == 4 and after_image .shape [0 ] > 1 :
83
85
after_image = after_image [0 :1 ]
84
86
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 )
90
89
91
90
# 计算总帧数
92
91
total_frames = int (duration * fps )
93
92
94
93
# 创建过渡帧
95
94
frames = []
96
95
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 )
106
104
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 )
116
116
117
117
# 合并所有帧
118
118
result = torch .cat (frames , dim = 0 )
119
119
120
120
return (result , duration , fps )
121
121
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 ):
123
127
# 获取目标尺寸(前图的尺寸)
124
128
before_height , before_width = before_image .shape [1 :3 ]
125
129
@@ -130,12 +134,10 @@ def check_and_resizee_size(self, before_image, after_image):
130
134
if before_height == after_height and before_width == after_width :
131
135
return after_image
132
136
133
-
134
137
# 计算宽高比
135
138
before_ratio = before_width / before_height
136
139
after_ratio = after_width / after_height
137
140
138
-
139
141
logger .debug (f"before_image: { before_image .shape } , after_image: { after_image .shape } " )
140
142
141
143
# 调整后图尺寸,填充满目标尺寸(可能需要裁剪)
@@ -168,12 +170,60 @@ def check_and_resizee_size(self, before_image, after_image):
168
170
169
171
return adjusted_after
170
172
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
+
171
219
NODE_CLASS_MAPPINGS = {
172
220
"FrameAdjuster" : FrameAdjuster ,
173
- "ImageTransitionLeftToRight" : ImageTransitionLeftToRight
221
+ "ImageTransitionLeftToRight" : ImageTransitionLeftToRight ,
222
+ "ImageTransitionTopToBottom" : ImageTransitionTopToBottom
174
223
}
175
224
176
225
NODE_DISPLAY_NAME_MAPPINGS = {
177
226
"FrameAdjuster" : "Frame Adjuster" ,
178
- "ImageTransitionLeftToRight" : "Image Transition Left to Right"
227
+ "ImageTransitionLeftToRight" : "Image Transition Left to Right" ,
228
+ "ImageTransitionTopToBottom" : "Image Transition Top to Bottom"
179
229
}
0 commit comments