add ImageCompareTransition node

This commit is contained in:
stormcenter
2024-12-14 12:27:08 +08:00
parent 9a0007c5d3
commit 7be1eb49fd
4 changed files with 1141 additions and 4 deletions
+30 -2
View File
@@ -10,6 +10,7 @@ A custom node for ComfyUI that allows you to create iPhone-compatible Live Photo
- Adjustable FPS and duration
- Optional audio support
- Standard output format compatible with iPhone
- Image transition effects with customizable parameters
![LivePhotoCreator](./example/Screenshot_2024-12-13_14-57-54.png)
@@ -61,13 +62,40 @@ The LivePhotoPreview node allows you to preview the created Live Photo:
- Input: Takes the video path from LivePhotoCreator
- Output: Interactive preview with hover effect
## Example Workflow
### ImageCompareTransition Node
The ImageCompareTransition node creates smooth transition effects between two images:
- **Inputs**:
- **image1**: First input image (IMAGE type)
- **image2**: Second input image (IMAGE type)
- **frames**: Number of transition frames (2-120 frames)
- **fps**: Frame rate of the transition (1-60 fps)
- **Output**:
- **frames**: Generated transition frame sequence
Features:
- Smooth left-to-right sliding transition effect
- Automatic image size matching
- Compatible with VHS video nodes for further processing
- Customizable frame count and frame rate
![Transition Demo](./example/Screenity_video_Dec_14_2024.mp4)
## Example Workflows
### Basic Live Photo Creation
1. Load your video using the "Load Video" node
2. Connect the video output to LivePhotoCreator
3. Configure the desired key frame, duration, and FPS
4. Connect LivePhotoPreview to see the result
5. The output files will be saved in the ComfyUI output directory under a timestamp-based folder
5. The output files will be saved in the ComfyUI output directory
### Image Transition Workflow
1. Load two images you want to transition between
2. Connect them to ImageCompareTransition node
3. Adjust frames and fps parameters
4. Use VHS nodes to save the transition as video
5. Check the example workflow in [haihyper_example.json](./example/haihyper_example.json)
## Output Format
Binary file not shown.
File diff suppressed because it is too large Load Diff
+106 -2
View File
@@ -224,12 +224,116 @@ class LivePhotoPreview:
print(f"[LivePhotoPreview] Executing with video path: {video}")
return {"ui": {"video": video}}
class ImageCompareTransition:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image1": ("IMAGE",), # 第一张图片
"image2": ("IMAGE",), # 第二张图片
"frames": ("INT", {
"default": 30,
"min": 2,
"max": 120,
"step": 1
}), # 过渡帧数
"fps": ("FLOAT", {
"default": 8.0,
"min": 1.0,
"max": 60.0,
"step": 1.0
})
}
}
RETURN_TYPES = ("IMAGE",) # 只返回帧序列
RETURN_NAMES = ("frames",)
FUNCTION = "create_transition"
CATEGORY = "image/animation"
def resize_image(self, img, target_h, target_w):
"""调整图片尺寸,保持长宽比"""
import torch
import torch.nn.functional as F
# 计算缩放比例
h, w = img.shape[1:3]
scale = min(target_h/h, target_w/w)
new_h = int(h * scale)
new_w = int(w * scale)
# 使用双线性插值进行缩放
img = img.unsqueeze(0) # 添加batch维度
img = F.interpolate(img, size=(new_h, new_w), mode='bilinear', align_corners=False)
img = img.squeeze(0) # 移除batch维度
return img
def create_transition(self, image1, image2, frames, fps):
import torch
import numpy as np
# 确保输入图像维度正确
if len(image1.shape) > 4:
image1 = image1.squeeze(0)
if len(image2.shape) > 4:
image2 = image2.squeeze(0)
# 打印输入图像的形状
print(f"Input image1 shape: {image1.shape}")
print(f"Input image2 shape: {image2.shape}")
# 获取两张图片的尺寸
h1, w1 = image1.shape[1:3]
h2, w2 = image2.shape[1:3]
# 使用较小的尺寸作为目标尺寸
target_h = min(h1, h2)
target_w = min(w1, w2)
# 调整两张图片的尺寸
if h1 != target_h or w1 != target_w:
image1 = self.resize_image(image1, target_h, target_w)
if h2 != target_h or w2 != target_w:
image2 = self.resize_image(image2, target_h, target_w)
# 创建帧列表
frame_list = []
# 生成过渡帧
for i in range(frames):
# 计算当前过渡位置(从0到1)
progress = i / (frames - 1)
# 计算分割点
split_pos = int(progress * target_w)
# 创建新帧 - 保持 [B, H, W, C] 格式
new_frame = torch.clone(image1)
new_frame[0, :, split_pos:, :] = image2[0, :, split_pos:, :]
frame_list.append(new_frame[0]) # 只保留 [H, W, C] 部分
# 将所有帧堆叠成一个张量
output_frames = torch.stack(frame_list)
# 确保数据在正确的范围内
output_frames = output_frames.clamp(0, 1)
# 打印调试信息
print(f"Single frame shape: {frame_list[0].shape}")
print(f"Output frames shape: {output_frames.shape}")
print(f"Output frames dtype: {output_frames.dtype}")
return (output_frames,)
NODE_CLASS_MAPPINGS = {
"LivePhotoCreator": LivePhotoCreator,
"LivePhotoPreview": LivePhotoPreview
"LivePhotoPreview": LivePhotoPreview,
"ImageCompareTransition": ImageCompareTransition
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LivePhotoCreator": "Create Live Photo",
"LivePhotoPreview": "Preview Live Photo"
"LivePhotoPreview": "Preview Live Photo",
"ImageCompareTransition": "Image Compare Transition"
}