diff --git a/README.md b/README.md index 24a51be..7f45ec2 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,9 @@ ## 📈 版本历史 ### 最新版本 +- **v3.0.0**(2025-09-05) +- 添加比例切分器节点 + - **v2.9.1**(2025-09-04) - 删除DD采样器节点,它已经不适用最新的CommyUI了 diff --git a/__init__.py b/__init__.py index c0178bc..dc36cee 100644 --- a/__init__.py +++ b/__init__.py @@ -11,6 +11,7 @@ from .node.model_switcher import NODE_CLASS_MAPPINGS as MODEL_SWITCHER_NODES from .node.condition_switcher import NODE_CLASS_MAPPINGS as CONDITION_SWITCHER_NODES from .node.latent_switcher import NODE_CLASS_MAPPINGS as LATENT_SWITCHER_NODES from .node.image_stroke import NODE_CLASS_MAPPINGS as IMAGE_STROKE_NODES +from .node.image_splitter import NODE_CLASS_MAPPINGS as IMAGE_SPLITTER_NODES # 导入Qwen-MT翻译节点 from .extensions.Qwen_MT.nodes import NODE_CLASS_MAPPINGS as QWEN_MT_NODES @@ -37,6 +38,7 @@ NODE_CLASS_MAPPINGS = { **CONDITION_SWITCHER_NODES, **LATENT_SWITCHER_NODES, **IMAGE_STROKE_NODES, + **IMAGE_SPLITTER_NODES, **QWEN_MT_NODES, **ASPECT_RATIO_NODES, } @@ -56,6 +58,7 @@ NODE_DISPLAY_NAME_MAPPINGS = { "DD-ConditionSwitcher": "DD Condition Switcher", "DD-LatentSwitcher": "DD Latent Switcher", "DD-ImageStroke": "DD Image Stroke", + "DD-ImageSplitter": "DD Image Splitter", "DD-QwenMTTranslator": "DD Qwen-MT", "DD-AspectRatioSelector": "DD Aspect Ratio Selector", } diff --git a/locales/en/nodeDefs.json b/locales/en/nodeDefs.json index 3d9cb14..ac7551a 100644 --- a/locales/en/nodeDefs.json +++ b/locales/en/nodeDefs.json @@ -323,6 +323,38 @@ } } }, + "DD-ImageSplitter": { + "display_name": "DD Image Splitter", + "description": "Split image by ratio and output specified part", + "inputs": { + "图像": { + "name": "Image", + "tooltip": "Input image to be split" + }, + "切分方向": { + "name": "Split Direction", + "tooltip": "Choose split direction: horizontal (left-right) or vertical (top-bottom)" + }, + "切分份数": { + "name": "Split Count", + "tooltip": "Number of parts to split the image into (2-10)" + }, + "输出位置": { + "name": "Output Position", + "tooltip": "Select which part to output (starting from 1)" + }, + "切分比例": { + "name": "Split Ratio", + "tooltip": "Split ratio, e.g., '1:1' for equal split, '2:1' for 2:1 ratio split" + } + }, + "outputs": { + "0": { + "name": "Image", + "tooltip": "Split image at specified position" + } + } + }, "DD-VideoFrameExtractor": { "display_name": "DD Video Frame Extractor", "description": "Extract first or last frame from video", diff --git a/locales/zh/nodeDefs.json b/locales/zh/nodeDefs.json index fdd3349..e6f35bf 100644 --- a/locales/zh/nodeDefs.json +++ b/locales/zh/nodeDefs.json @@ -323,6 +323,38 @@ } } }, + "DD-ImageSplitter": { + "display_name": "DD 图像切分器", + "description": "按比例切分图像并输出指定部分", + "inputs": { + "图像": { + "name": "图像", + "tooltip": "需要切分的输入图像" + }, + "切分方向": { + "name": "切分方向", + "tooltip": "选择切分方向:左右切分或上下切分" + }, + "切分份数": { + "name": "切分份数", + "tooltip": "将图像切分成多少份(2-10)" + }, + "输出位置": { + "name": "输出位置", + "tooltip": "选择输出第几份切分的图像(1开始计数)" + }, + "切分比例": { + "name": "切分比例", + "tooltip": "切分比例,如'1:1'表示均等切分,'2:1'表示2:1比例切分" + } + }, + "outputs": { + "0": { + "name": "图像", + "tooltip": "切分后的指定位置图像" + } + } + }, "DD-VideoFrameExtractor": { "display_name": "DD 视频首尾帧输出", "description": "从视频中提取首帧或尾帧图像", diff --git a/node/image_splitter.py b/node/image_splitter.py new file mode 100644 index 0000000..4da18dc --- /dev/null +++ b/node/image_splitter.py @@ -0,0 +1,132 @@ +import torch +import numpy as np +from PIL import Image + +class DDImageSplitter: + """ + DD 图像切分器 + 支持按比例切分图像并选择输出指定部分 + """ + + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "图像": ("IMAGE",), + "切分方向": (["左右", "上下"], {"default": "左右"}), + "切分份数": ("INT", {"default": 2, "min": 2, "max": 10, "step": 1}), + "输出位置": ("INT", {"default": 1, "min": 1, "max": 10, "step": 1}), + "切分比例": ("STRING", {"default": "1:1", "multiline": False}), + } + } + + RETURN_TYPES = ("IMAGE",) + RETURN_NAMES = ("图像",) + FUNCTION = "split_image" + CATEGORY = "🍺DD系列节点" + + def split_image(self, 图像, 切分方向, 切分份数, 输出位置, 切分比例): + """ + 切分图像并返回指定位置的部分 + """ + # 确保输出位置在有效范围内 + if 输出位置 > 切分份数: + 输出位置 = 切分份数 + + # 转换tensor到PIL Image + image_tensor = 图像[0] if len(图像.shape) == 4 else 图像 + image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8) + image_pil = Image.fromarray(image_np) + + width, height = image_pil.size + + # 解析切分比例 + ratios = self.parse_ratios(切分比例, 切分份数) + + if 切分方向 == "左右": + # 左右切分 + split_image = self.split_horizontal(image_pil, ratios, 输出位置) + else: + # 上下切分 + split_image = self.split_vertical(image_pil, ratios, 输出位置) + + # 转换回tensor + result_np = np.array(split_image).astype(np.float32) / 255.0 + result_tensor = torch.from_numpy(result_np).unsqueeze(0) + + return (result_tensor,) + + def parse_ratios(self, 切分比例, 切分份数): + """ + 解析切分比例字符串 + """ + try: + # 解析比例字符串,如 "1:1" 或 "2:1:3" + parts = 切分比例.strip().split(':') + if len(parts) == 切分份数: + ratios = [float(p) for p in parts] + elif len(parts) == 2 and 切分份数 == 2: + ratios = [float(parts[0]), float(parts[1])] + else: + # 如果比例数量不匹配,使用均等比例 + ratios = [1.0] * 切分份数 + except: + # 解析失败时使用均等比例 + ratios = [1.0] * 切分份数 + + # 标准化比例 + total = sum(ratios) + return [r / total for r in ratios] + + def split_horizontal(self, image, ratios, 输出位置): + """ + 水平切分(左右切分) + """ + width, height = image.size + + # 计算每部分的宽度 + widths = [int(width * ratio) for ratio in ratios] + + # 调整最后一个宽度以确保总和等于原宽度 + widths[-1] = width - sum(widths[:-1]) + + # 计算切分位置的起始x坐标 + start_x = sum(widths[:输出位置-1]) + end_x = start_x + widths[输出位置-1] + + # 裁剪图像 + cropped_image = image.crop((start_x, 0, end_x, height)) + + return cropped_image + + def split_vertical(self, image, ratios, 输出位置): + """ + 垂直切分(上下切分) + """ + width, height = image.size + + # 计算每部分的高度 + heights = [int(height * ratio) for ratio in ratios] + + # 调整最后一个高度以确保总和等于原高度 + heights[-1] = height - sum(heights[:-1]) + + # 计算切分位置的起始y坐标 + start_y = sum(heights[:输出位置-1]) + end_y = start_y + heights[输出位置-1] + + # 裁剪图像 + cropped_image = image.crop((0, start_y, width, end_y)) + + return cropped_image + + +# 节点类映射 +NODE_CLASS_MAPPINGS = { + "DD-ImageSplitter": DDImageSplitter +} + +# 节点显示名称映射 +NODE_DISPLAY_NAME_MAPPINGS = { + "DD-ImageSplitter": "DD Image Splitter" +}