Comfyui学习笔记(三):自定义节点添加

1.自定义节点

自定义节点是ComfyUI的扩展插件,能够增加新功能,如高级图像处理、机器学习微调、颜色调整等。这些节点由社区开发,可显著扩展ComfyUI的基础功能。

2.自定义节点安装

所有自定义节点安装都需要完成下面两个步骤

  • (1) 克隆节点代码到ComfyUI/custom_nodes目录下
  • (2) 安装对应python项目依赖:pip install -r requirements.txt

安装方法有三种:

方法 优点 缺点
ComfyUI Manager (推荐) 1. 自动化安装 2. 依赖处理 3. 图形界面 不在 registry 中注册的节点无法通过 Manager 直接搜索到
Git 克隆 可以安装不在 registry 中注册的节点 1. 需要Git知识 2. 手动处理依赖 3. 存在安装风险
ZIP 下载 1. 无需Git 2. 手动处理一切 1. 需要手动处理依赖 2. 无版本控制 3. 存在安装风险

2.1 ComfyUI-Manager

 这个前面已经详细介绍过了,也是官方推荐的方法。

2.2 Git 克隆

  • (1) 去对应插件的github仓库获取克隆地址;
  • (2) 进入custom_nodes目录:
1
>> cd /path/to/ComfyUI/custom_nodes
  • (3) 克隆仓库
1
>> git clone <插件克隆的git地址>
  • (4) 安装依赖:
1
2
>> cd /path/to/ComfyUI/custom_nodes/<插件名>
>> pip install -r requirements.txt
  • (5) 重启ComfyUI服务,刷新浏览器

2.3 Zip下载

  • (1) 去对应插件的github仓库下载Zip包;
  • (2) 进入custom_nodes目录:
1
>> cd /path/to/ComfyUI/custom_nodes
  • (3) 解压zip包
1
2
3
# 1.将zip包拷贝到当前路径下
# 2.解压zip包
>> unzip <zip包名>.zip
  • (4) 安装依赖:
1
2
>> cd /path/to/ComfyUI/custom_nodes/<插件名>
>> pip install -r requirements.txt
  • (5) 重启ComfyUI服务,刷新浏览器

3.添加自定义节点

3.1 定义一个反转节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class InvertImageNode:
@classmethod
def INPUT_TYPES(cls):
return {
# 一个名为image_in的必须输入,类型为IMAGE,无额外参数
"required": { "image_in" : ("IMAGE", {}) },
}

RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image_out",)
CATEGORY = "examples"
FUNCTION = "invert"

def invert(self, image_in):
image_out = 1 - image_in
return (image_out,)

每个自定义节点都是一个Python类,具有以下关键属性:

  • (1) INPUT_TYPES:定义节点输入。该方法返回一个字典,必须包含required键,也可以包含optionalhidden键。requiredoptional输入唯一区别在于,optional输入可以不连接。每个键又是一个字典,其中键值对指定输入的名称和类型。类型由一个tuple定义,第一个元素为数据类型,第二个参数包含附件参数的字典。
  • (2) RETURN_TYPES:定义了节点返回数据类型。如果节点没有输出,也必须提供RETURN_TYPES = (),如果只有一个输出,也要加上逗号标记一下(RETURN_TYPES = ('IMAGE', )),这是Python创建元组所必须的。
  • (3) CATEGORY:定义节点在ComfyUI添加节点菜单中的分类。可以使用路径指定子菜单,如examples/trivial
  • (4) FUNCTION:定义节点执行时应调用的Python函数名。
  • (5) 指定控制扩展:
字段 描述
OUTPUT_NODE 默认情况下,节点不会被视为输出节点,设置OUTPUT_NODE=True可以指定该节点为输出节点
IS_CHANGED 默认情况下,如果节点的任何输入或小部件发生变化,ComfyUI会认为该节点已更改。这通常是正确的,但在某些情况下可能需要重写此行为。例如,你希望节点始终被认为已更改,可以return float("NaN"),
SEARCH_ALIASES 可选。用户搜索此节点时可能使用的替代名称列表。 此属性会包含在 /object_infoAPI 响应的 search_aliases 字段中。

IS_CHANGED 接收与主函数(由 FUNCTION 指定)相同的参数,并可以返回任意 Python 对象。该对象会与上次运行时返回的对象进行比较,如果 is_changed != is_changed_old,则认为节点已更改(相关代码在 execution.py 中)。

一个实际检查变化的好例子是内置的/path/to/ComfyUI/nodes.pyLoadImage 节点的代码,它会加载图片并返回哈希值:

1
2
3
4
5
6
7
@classmethod
def IS_CHANGED(s, image):
image_path = folder_paths.get_annotated_filepath(image)
m = hashlib.sha256()
with open(image_path, 'rb') as f:
m.update(f.read())
return m.digest().hex()

3.2 注册节点

1
2
3
4
5
6
7
# 节点注册
NODE_CLASS_MAPPINGS = {
"InvertImageNode": InvertImageNode
}
NODE_DISPLAY_NAME_MAPPINGS = {
"InvertImageNode": "反转节点"
}

3.3 添加节点导入

 新建__init__.py文件,内容如下:

1
2
3
4
5
6
7
8
9
10
from .invert_image_node import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS

__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]

# 添加一下打印信息
print("\n" + "="*60)
print("✅ ComfyUI自定义节点加载成功: invert")
print(" 节点: 图像反转")
print(" 分类: examples")
print("="*60 + "\n")

参考资料