@@ -93,6 +93,10 @@ def INPUT_TYPES(cls):
93
93
},
94
94
"optional" : {
95
95
"bounce_back" : ("BOOLEAN" , {"default" : False }),
96
+ "start_end_pause_percent" : ("FLOAT" , {"default" : 0.09 , "min" : 0.0 , "max" : 0.5 , "step" : 0.01 }),
97
+ "middle_pause_percent" : ("FLOAT" , {"default" : 0.15 , "min" : 0.0 , "max" : 0.5 , "step" : 0.01 }),
98
+ "start_end_position_percent" : ("FLOAT" , {"default" : 0.06 , "min" : 0.0 , "max" : 0.5 , "step" : 0.01 }),
99
+ "transition_line_width" : ("INT" , {"default" : 8 , "min" : 1 , "max" : 20 , "step" : 1 }),
96
100
}
97
101
}
98
102
@@ -101,7 +105,7 @@ def INPUT_TYPES(cls):
101
105
FUNCTION = "create_transition"
102
106
CATEGORY = "utils"
103
107
104
- def create_transition (self , before_image : torch .Tensor , after_image : torch .Tensor , duration : float , fps : float , bounce_back : bool = False ):
108
+ def create_transition (self , before_image : torch .Tensor , after_image : torch .Tensor , duration : float , fps : float , bounce_back : bool = False , start_end_pause_percent : float = 0 , middle_pause_percent : float = 0 , start_end_position_percent : float = 0 , transition_line_width : int = 1 ):
105
109
# 确保输入是单张图片,如果是批次则取第一张
106
110
if len (before_image .shape ) == 4 and before_image .shape [0 ] > 1 :
107
111
before_image = before_image [0 :1 ]
@@ -119,31 +123,68 @@ def create_transition(self, before_image: torch.Tensor, after_image: torch.Tenso
119
123
120
124
if bounce_back :
121
125
# 如果启用回弹效果,先从左到右,再从右到左
122
- # 前半段:从左到右
123
- half_frames = total_frames // 2
124
- for i in range (half_frames ):
125
- progress = i / (half_frames - 1 ) if half_frames > 1 else 1.0
126
- new_frame = self .create_transition_frame (before_image , adjusted_after , progress )
126
+ # 计算各阶段的帧数
127
+ start_pause_frames = int (total_frames * start_end_pause_percent )
128
+ middle_pause_frames = int (total_frames * middle_pause_percent )
129
+ transition_frames = (total_frames - 2 * start_pause_frames - middle_pause_frames ) // 2
130
+
131
+ # 第一阶段:起始停留(显示前图)
132
+ for i in range (start_pause_frames ):
133
+ frames .append (before_image .clone ())
134
+
135
+ # 第二阶段:从左到右过渡
136
+ for i in range (transition_frames ):
137
+ progress = i / (transition_frames - 1 ) if transition_frames > 1 else 1.0
138
+ # 调整进度以考虑起始和结束位置
139
+ adjusted_progress = start_end_position_percent + (1.0 - 2 * start_end_position_percent ) * progress
140
+ new_frame = self .create_transition_frame (before_image , adjusted_after , adjusted_progress , transition_line_width )
127
141
frames .append (new_frame )
128
142
129
- # 后半段:从右到左
130
- for i in range (half_frames , total_frames ):
131
- progress = 1.0 - ((i - half_frames ) / (total_frames - half_frames - 1 ) if total_frames - half_frames > 1 else 0.0 )
132
- new_frame = self .create_transition_frame (before_image , adjusted_after , progress )
143
+ # 第三阶段:中间停留(显示后图)
144
+ for i in range (middle_pause_frames ):
145
+ frames .append (adjusted_after .clone ())
146
+
147
+ # 第四阶段:从右到左过渡
148
+ for i in range (transition_frames ):
149
+ progress = i / (transition_frames - 1 ) if transition_frames > 1 else 1.0
150
+ # 调整进度以考虑起始和结束位置,反向
151
+ adjusted_progress = 1.0 - start_end_position_percent - (1.0 - 2 * start_end_position_percent ) * progress
152
+ new_frame = self .create_transition_frame (before_image , adjusted_after , adjusted_progress , transition_line_width )
133
153
frames .append (new_frame )
154
+
155
+ # 第五阶段:结束停留(显示前图)
156
+ remaining_frames = total_frames - len (frames )
157
+ for i in range (remaining_frames ):
158
+ frames .append (before_image .clone ())
134
159
else :
135
160
# 正常的单向过渡
136
- for i in range (total_frames ):
137
- progress = i / (total_frames - 1 ) if total_frames > 1 else 1.0
138
- new_frame = self .create_transition_frame (before_image , adjusted_after , progress )
161
+ # 计算各阶段的帧数
162
+ start_pause_frames = int (total_frames * start_end_pause_percent )
163
+ transition_frames = total_frames - 2 * start_pause_frames
164
+
165
+ # 第一阶段:起始停留(显示前图)
166
+ for i in range (start_pause_frames ):
167
+ frames .append (before_image .clone ())
168
+
169
+ # 第二阶段:过渡
170
+ for i in range (transition_frames ):
171
+ progress = i / (transition_frames - 1 ) if transition_frames > 1 else 1.0
172
+ # 调整进度以考虑起始和结束位置
173
+ adjusted_progress = start_end_position_percent + (1.0 - 2 * start_end_position_percent ) * progress
174
+ new_frame = self .create_transition_frame (before_image , adjusted_after , adjusted_progress , transition_line_width )
139
175
frames .append (new_frame )
176
+
177
+ # 第三阶段:结束停留(显示后图)
178
+ remaining_frames = total_frames - len (frames )
179
+ for i in range (remaining_frames ):
180
+ frames .append (adjusted_after .clone ())
140
181
141
182
# 合并所有帧
142
183
result = torch .cat (frames , dim = 0 )
143
184
144
185
return (result , duration , fps )
145
186
146
- def create_transition_frame (self , before_image : torch .Tensor , after_image : torch .Tensor , progress : float ):
187
+ def create_transition_frame (self , before_image : torch .Tensor , after_image : torch .Tensor , progress : float , line_width : int = 2 ):
147
188
"""创建过渡帧的抽象方法,子类需要实现"""
148
189
raise NotImplementedError ("子类必须实现create_transition_frame方法" )
149
190
@@ -197,7 +238,7 @@ def check_and_resize_size(self, before_image, after_image):
197
238
class ImageTransitionLeftToRight (ImageTransitionBase ):
198
239
"""从左到右的图像过渡效果"""
199
240
200
- def create_transition_frame (self , before_image : torch .Tensor , after_image : torch .Tensor , progress : float ):
241
+ def create_transition_frame (self , before_image : torch .Tensor , after_image : torch .Tensor , progress : float , line_width : int = 2 ):
201
242
# 获取目标尺寸(前图的尺寸)
202
243
_ , target_width = before_image .shape [1 :3 ]
203
244
@@ -215,12 +256,21 @@ def create_transition_frame(self, before_image: torch.Tensor, after_image: torch
215
256
if transition_x > 0 :
216
257
new_frame [0 , :, :transition_x , :] = after_image [0 , :, :transition_x , :]
217
258
259
+ # 添加白色过渡线条
260
+ if line_width > 0 and transition_x > 0 and transition_x < target_width :
261
+ # 计算线条的起始和结束位置
262
+ line_start = max (0 , transition_x - line_width // 2 )
263
+ line_end = min (target_width , transition_x + line_width // 2 )
264
+
265
+ # 用白色填充线条区域
266
+ new_frame [0 , :, line_start :line_end , :] = 1.0
267
+
218
268
return new_frame
219
269
220
270
class ImageTransitionTopToBottom (ImageTransitionBase ):
221
271
"""从上到下的图像过渡效果"""
222
272
223
- def create_transition_frame (self , before_image : torch .Tensor , after_image : torch .Tensor , progress : float ):
273
+ def create_transition_frame (self , before_image : torch .Tensor , after_image : torch .Tensor , progress : float , line_width : int = 2 ):
224
274
# 获取目标尺寸(前图的尺寸)
225
275
target_height , _ = before_image .shape [1 :3 ]
226
276
@@ -238,16 +288,93 @@ def create_transition_frame(self, before_image: torch.Tensor, after_image: torch
238
288
if transition_y > 0 :
239
289
new_frame [0 , :transition_y , :, :] = after_image [0 , :transition_y , :, :]
240
290
291
+ # 添加白色过渡线条
292
+ if line_width > 0 and transition_y > 0 and transition_y < target_height :
293
+ # 计算线条的起始和结束位置
294
+ line_start = max (0 , transition_y - line_width // 2 )
295
+ line_end = min (target_height , transition_y + line_width // 2 )
296
+
297
+ # 用白色填充线条区域
298
+ new_frame [0 , line_start :line_end , :, :] = 1.0
299
+
300
+ return new_frame
301
+
302
+ class ImageTransitionBottomToTop (ImageTransitionBase ):
303
+ """从底到顶的图像过渡效果"""
304
+
305
+ def create_transition_frame (self , before_image : torch .Tensor , after_image : torch .Tensor , progress : float , line_width : int = 2 ):
306
+ # 获取目标尺寸(前图的尺寸)
307
+ target_height , _ = before_image .shape [1 :3 ]
308
+
309
+ # 计算过渡线的y坐标(从底部开始)
310
+ transition_y = int (target_height * (1.0 - progress ))
311
+
312
+ # 创建新帧
313
+ new_frame = torch .zeros_like (before_image )
314
+
315
+ # 从底到顶过渡:下方显示后图,上方显示前图
316
+ # 先填充整个前图
317
+ new_frame [0 ] = before_image [0 ]
318
+
319
+ # 然后在下方填充后图(覆盖前图)
320
+ if transition_y < target_height :
321
+ new_frame [0 , transition_y :, :, :] = after_image [0 , transition_y :, :, :]
322
+
323
+ # 添加白色过渡线条
324
+ if line_width > 0 and transition_y > 0 and transition_y < target_height :
325
+ # 计算线条的起始和结束位置
326
+ line_start = max (0 , transition_y - line_width // 2 )
327
+ line_end = min (target_height , transition_y + line_width // 2 )
328
+
329
+ # 用白色填充线条区域
330
+ new_frame [0 , line_start :line_end , :, :] = 1.0
331
+
332
+ return new_frame
333
+
334
+ class ImageTransitionRightToLeft (ImageTransitionBase ):
335
+ """从右到左的图像过渡效果"""
336
+
337
+ def create_transition_frame (self , before_image : torch .Tensor , after_image : torch .Tensor , progress : float , line_width : int = 2 ):
338
+ # 获取目标尺寸(前图的尺寸)
339
+ _ , target_width = before_image .shape [1 :3 ]
340
+
341
+ # 计算过渡线的x坐标(从右侧开始)
342
+ transition_x = int (target_width * (1.0 - progress ))
343
+
344
+ # 创建新帧
345
+ new_frame = torch .zeros_like (before_image )
346
+
347
+ # 从右到左过渡:右侧显示后图,左侧显示前图
348
+ # 先填充整个前图
349
+ new_frame [0 ] = before_image [0 ]
350
+
351
+ # 然后在右侧填充后图(覆盖前图)
352
+ if transition_x < target_width :
353
+ new_frame [0 , :, transition_x :, :] = after_image [0 , :, transition_x :, :]
354
+
355
+ # 添加白色过渡线条
356
+ if line_width > 0 and transition_x > 0 and transition_x < target_width :
357
+ # 计算线条的起始和结束位置
358
+ line_start = max (0 , transition_x - line_width // 2 )
359
+ line_end = min (target_width , transition_x + line_width // 2 )
360
+
361
+ # 用白色填充线条区域
362
+ new_frame [0 , :, line_start :line_end , :] = 1.0
363
+
241
364
return new_frame
242
365
243
366
NODE_CLASS_MAPPINGS = {
244
367
"FrameAdjuster" : FrameAdjuster ,
245
368
"ImageTransitionLeftToRight" : ImageTransitionLeftToRight ,
246
- "ImageTransitionTopToBottom" : ImageTransitionTopToBottom
369
+ "ImageTransitionTopToBottom" : ImageTransitionTopToBottom ,
370
+ "ImageTransitionRightToLeft" : ImageTransitionRightToLeft ,
371
+ "ImageTransitionBottomToTop" : ImageTransitionBottomToTop
247
372
}
248
373
249
374
NODE_DISPLAY_NAME_MAPPINGS = {
250
375
"FrameAdjuster" : "Frame Adjuster" ,
251
376
"ImageTransitionLeftToRight" : "Image Transition Left to Right" ,
252
- "ImageTransitionTopToBottom" : "Image Transition Top to Bottom"
377
+ "ImageTransitionTopToBottom" : "Image Transition Top to Bottom" ,
378
+ "ImageTransitionRightToLeft" : "Image Transition Right to Left" ,
379
+ "ImageTransitionBottomToTop" : "Image Transition Bottom to Top"
253
380
}
0 commit comments