fix: 八方向拆分不再切断角色;全仓库参数补齐中文 tooltip
【修复】角色被格线切断(脚、手杖、飘起的斗篷被削掉) 新增 expand_beyond_cell(默认开启):格子只用来判定「这是哪个方向」, 角色的实际范围由它自身的连通区域决定,按质心归属确保邻居不混入。 实测 8/8 方向的裁剪框边缘 alpha 从 1.00(内容顶到边界=被切断) 降到 0.00,S 方向高度 326→356、E 方向宽度 150→188 把缺的部分找了回来。 代价是需要两遍扫描(先求全序列并集框再提取),耗时 4.7s→14.9s。 【规则】每个参数都必须有中文 tooltip,作为以后的统一约定 全仓库 26 个节点 169 个参数,此前缺 115 个,现已 100% 覆盖。 tooltip 写「怎么调」而不只是「是什么」:给取值区间的实际影响、 推荐值与踩坑提示(如 OpenAI/ZenMux 的地址栏不能带 :// , 素材拆分节点用于动画序列时顺序会漂移等)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
28fd14aaad
commit
5d3834503e
+20
-4
@@ -30,10 +30,26 @@ class ColorMatcherNode:
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"reference_image": ("IMAGE",),
|
||||
"moving_image": ("IMAGE",),
|
||||
"match_method": (["histogram", "mean_std", "none"], {"default": "histogram"}),
|
||||
"blend_factor": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"reference_image": ("IMAGE", {
|
||||
"tooltip": "参考图:提供目标色调,本身不会被改动。"
|
||||
}),
|
||||
"moving_image": ("IMAGE", {
|
||||
"tooltip": "待校色图:它的颜色分布会被改造成参考图的样子。"
|
||||
}),
|
||||
"match_method": (["histogram", "mean_std", "none"], {
|
||||
"default": "histogram",
|
||||
"tooltip": "匹配算法:\n"
|
||||
"histogram = 逐通道直方图匹配,色调贴合最紧,\n"
|
||||
" 但两图内容差异大时容易出偏色\n"
|
||||
"mean_std = 只对齐均值与标准差,效果温和、不易翻车\n"
|
||||
"none = 不做匹配,仅用于对照原图"
|
||||
}),
|
||||
"blend_factor": ("FLOAT", {
|
||||
"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01,
|
||||
"tooltip": "匹配强度:结果在原图与完全匹配之间线性混合。\n"
|
||||
"0 = 保持原样,1 = 完全套用参考图色调。\n"
|
||||
"匹配过头显得失真时降到 0.5~0.8 往往更自然。"
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,10 @@ class DialogueExtractorNode:
|
||||
"required": {
|
||||
"input_text": ("STRING", {
|
||||
"multiline": True,
|
||||
"default": ""
|
||||
"default": "",
|
||||
"tooltip": "分镜描述原文。节点会从中挑出旁白/对白部分,\n"
|
||||
"画面描述、镜头调度等非台词内容会被滤掉。\n"
|
||||
"输出为对白列表,可直接接配音或字幕环节。"
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
+146
-40
@@ -93,6 +93,41 @@ def _drop_fragments(alpha, ratio):
|
||||
return np.where(keep[lab], alpha, 0.0).astype(np.float32)
|
||||
|
||||
|
||||
def _assign_blocks(alpha_full, ybnd, xbnd, cols, frag_ratio):
|
||||
"""
|
||||
全图连通标记 + 按质心把每块归属到格子。
|
||||
|
||||
这样格子只负责回答「这是哪个方向」,角色的实际范围由它自己的连通块决定,
|
||||
因此**角色超出格子边界也不会被切**(原本严格等分会把探出去的脚、
|
||||
飘起的斗篷直接截断)。归属按质心判定,每块只属于一个格子,
|
||||
相邻角色不会被重复计入。
|
||||
|
||||
返回 (lab, {cell_id: [块标签...]});scipy 不可用时返回 (None, None)。
|
||||
"""
|
||||
if not _HAS_SCIPY:
|
||||
return None, None
|
||||
solid = alpha_full > 0.1
|
||||
if not solid.any():
|
||||
return None, {}
|
||||
lab, n = ndi.label(solid)
|
||||
if n == 0:
|
||||
return lab, {}
|
||||
areas = np.bincount(lab.ravel())
|
||||
areas[0] = 0
|
||||
big = areas.max()
|
||||
cents = ndi.center_of_mass(solid, lab, np.arange(1, n + 1))
|
||||
rows = len(ybnd) - 1
|
||||
out = {}
|
||||
for i in range(1, n + 1):
|
||||
if frag_ratio > 0 and areas[i] < big * float(frag_ratio):
|
||||
continue # 碎片,丢弃
|
||||
cy, cx = cents[i - 1]
|
||||
r = min(rows - 1, max(0, int(np.searchsorted(ybnd, cy, "right") - 1)))
|
||||
c = min(cols - 1, max(0, int(np.searchsorted(xbnd, cx, "right") - 1)))
|
||||
out.setdefault(r * cols + c, []).append(i)
|
||||
return lab, out
|
||||
|
||||
|
||||
def _bbox(alpha, thr=0.02):
|
||||
"""内容包围盒 (y0,y1,x0,x1),无内容时返回 None。"""
|
||||
m = alpha > thr
|
||||
@@ -173,6 +208,15 @@ class RuiEightDirSplit:
|
||||
"切进本格,既难看又会撑大自动裁剪的范围。\n"
|
||||
"0 = 不清理;与身体相连的道具不会被误删。"
|
||||
}),
|
||||
"expand_beyond_cell": ("BOOLEAN", {
|
||||
"default": True,
|
||||
"tooltip": "允许角色超出格子边界(强烈建议开启)。\n"
|
||||
"关闭时按格子严格切分,角色只要探出格线就会被切断\n"
|
||||
"——最常见的是脚、飘起的斗篷和手杖被削掉一截。\n"
|
||||
"开启后格子只用来判定「这是哪个方向」,实际范围由角色\n"
|
||||
"自身的连通区域决定,因此不会被切;按质心归属,\n"
|
||||
"相邻角色也不会被卷进来。"
|
||||
}),
|
||||
"auto_crop": ("BOOLEAN", {
|
||||
"default": True,
|
||||
"tooltip": "按内容裁掉多余空白。\n"
|
||||
@@ -203,7 +247,8 @@ class RuiEightDirSplit:
|
||||
|
||||
def split(self, images, grid_cols, grid_rows, empty_cells,
|
||||
direction_names, bg_mode, bg_threshold, edge_softness,
|
||||
fragment_threshold, auto_crop, crop_padding, masks=None):
|
||||
fragment_threshold, expand_beyond_cell, auto_crop, crop_padding,
|
||||
masks=None):
|
||||
mode = _BG_MODES.get(bg_mode, "white")
|
||||
B, H, W, C = images.shape
|
||||
cols, rows = int(grid_cols), int(grid_rows)
|
||||
@@ -234,49 +279,110 @@ class RuiEightDirSplit:
|
||||
ybnd = [int(round(r * H / rows)) for r in range(rows + 1)]
|
||||
xbnd = [int(round(c * W / cols)) for c in range(cols + 1)]
|
||||
|
||||
# ---- 第一遍:切格 + 生成 alpha,同时累计每个方向的内容包围盒 ----
|
||||
per_dir = [[] for _ in range(n_dir)]
|
||||
boxes = [None] * n_dir
|
||||
for b in range(B):
|
||||
pad = int(crop_padding)
|
||||
use_expand = bool(expand_beyond_cell) and mode != "none" and _HAS_SCIPY
|
||||
|
||||
def frame_alpha(b):
|
||||
if mode == "white":
|
||||
return _white_to_alpha(rgb_all[b], bg_threshold, edge_softness)
|
||||
if mode == "keep" and a_in is not None:
|
||||
return a_in[b]
|
||||
return np.ones((H, W), dtype=np.float32)
|
||||
|
||||
outs, notes = [], []
|
||||
|
||||
if use_expand:
|
||||
# ===== 内容自适应:格子只定方向,范围由角色自身的连通块决定 =====
|
||||
# 第一遍只求包围盒(全图坐标),不留像素,避免整段序列驻留内存
|
||||
boxes = [None] * n_dir
|
||||
for b in range(B):
|
||||
lab, groups = _assign_blocks(frame_alpha(b), ybnd, xbnd,
|
||||
cols, fragment_threshold)
|
||||
if lab is None:
|
||||
continue
|
||||
for di, cid in enumerate(cell_ids):
|
||||
blk = groups.get(cid)
|
||||
if not blk:
|
||||
continue
|
||||
bb = _bbox(np.isin(lab, blk).astype(np.float32), 0.5)
|
||||
if bb is None:
|
||||
continue
|
||||
boxes[di] = bb if boxes[di] is None else (
|
||||
min(boxes[di][0], bb[0]), max(boxes[di][1], bb[1]),
|
||||
min(boxes[di][2], bb[2]), max(boxes[di][3], bb[3]))
|
||||
|
||||
# 没有 auto_crop 时退回该格的格线范围,仍允许块超界的像素带出来
|
||||
final = []
|
||||
for di, cid in enumerate(cell_ids):
|
||||
r, c = divmod(cid, cols)
|
||||
y0, y1, x0, x1 = ybnd[r], ybnd[r + 1], xbnd[c], xbnd[c + 1]
|
||||
rgb = rgb_all[b, y0:y1, x0:x1]
|
||||
if mode == "white":
|
||||
alpha = _white_to_alpha(rgb, bg_threshold, edge_softness)
|
||||
elif mode == "keep" and a_in is not None:
|
||||
alpha = a_in[b, y0:y1, x0:x1]
|
||||
if auto_crop and boxes[di] is not None:
|
||||
y0, y1, x0, x1 = boxes[di]
|
||||
y0 = max(0, y0 - pad); x0 = max(0, x0 - pad)
|
||||
y1 = min(H, y1 + pad); x1 = min(W, x1 + pad)
|
||||
elif boxes[di] is not None:
|
||||
y0, y1, x0, x1 = (min(ybnd[r], boxes[di][0]),
|
||||
max(ybnd[r + 1], boxes[di][1]),
|
||||
min(xbnd[c], boxes[di][2]),
|
||||
max(xbnd[c + 1], boxes[di][3]))
|
||||
else:
|
||||
alpha = np.ones(rgb.shape[:2], dtype=np.float32)
|
||||
if mode != "none":
|
||||
alpha = _drop_fragments(alpha, fragment_threshold)
|
||||
per_dir[di].append((rgb, alpha))
|
||||
if auto_crop:
|
||||
bb = _bbox(alpha)
|
||||
if bb is not None:
|
||||
boxes[di] = bb if boxes[di] is None else (
|
||||
min(boxes[di][0], bb[0]), max(boxes[di][1], bb[1]),
|
||||
min(boxes[di][2], bb[2]), max(boxes[di][3], bb[3]))
|
||||
y0, y1, x0, x1 = ybnd[r], ybnd[r + 1], xbnd[c], xbnd[c + 1]
|
||||
final.append((y0, y1, x0, x1))
|
||||
outs.append(np.zeros((B, y1 - y0, x1 - x0, 4), dtype=np.float32))
|
||||
|
||||
# ---- 第二遍:按并集包围盒统一裁剪并打包 ----
|
||||
outs, notes = [], []
|
||||
pad = int(crop_padding)
|
||||
for di in range(n_dir):
|
||||
frames = per_dir[di]
|
||||
ch, cw = frames[0][0].shape[:2]
|
||||
if auto_crop and boxes[di] is not None:
|
||||
y0, y1, x0, x1 = boxes[di]
|
||||
y0 = max(0, y0 - pad); x0 = max(0, x0 - pad)
|
||||
y1 = min(ch, y1 + pad); x1 = min(cw, x1 + pad)
|
||||
else:
|
||||
y0, y1, x0, x1 = 0, ch, 0, cw
|
||||
stack = np.empty((len(frames), y1 - y0, x1 - x0, 4), dtype=np.float32)
|
||||
for fi, (rgb, alpha) in enumerate(frames):
|
||||
stack[fi, ..., :3] = rgb[y0:y1, x0:x1]
|
||||
stack[fi, ..., 3] = alpha[y0:y1, x0:x1]
|
||||
outs.append(torch.from_numpy(stack))
|
||||
notes.append(f"{di + 1}.{names[di]} 格{cell_ids[di]} "
|
||||
f"{x1 - x0}×{y1 - y0}")
|
||||
# 第二遍按并集框提取;只保留归属本格的连通块,邻居不会混进来
|
||||
for b in range(B):
|
||||
af = frame_alpha(b)
|
||||
lab, groups = _assign_blocks(af, ybnd, xbnd, cols, fragment_threshold)
|
||||
for di, cid in enumerate(cell_ids):
|
||||
y0, y1, x0, x1 = final[di]
|
||||
outs[di][b, ..., :3] = rgb_all[b, y0:y1, x0:x1]
|
||||
blk = groups.get(cid) if groups else None
|
||||
if not blk:
|
||||
continue
|
||||
m = np.isin(lab[y0:y1, x0:x1], blk)
|
||||
outs[di][b, ..., 3] = af[y0:y1, x0:x1] * m
|
||||
|
||||
for di in range(n_dir):
|
||||
y0, y1, x0, x1 = final[di]
|
||||
notes.append(f"{di + 1}.{names[di]} 格{cell_ids[di]} "
|
||||
f"{x1 - x0}×{y1 - y0}")
|
||||
outs[di] = torch.from_numpy(outs[di])
|
||||
else:
|
||||
# ===== 严格按格线切分(角色探出格线会被截断)=====
|
||||
per_dir = [[] for _ in range(n_dir)]
|
||||
boxes = [None] * n_dir
|
||||
for b in range(B):
|
||||
af = frame_alpha(b)
|
||||
for di, cid in enumerate(cell_ids):
|
||||
r, c = divmod(cid, cols)
|
||||
y0, y1, x0, x1 = ybnd[r], ybnd[r + 1], xbnd[c], xbnd[c + 1]
|
||||
rgb = rgb_all[b, y0:y1, x0:x1]
|
||||
alpha = af[y0:y1, x0:x1]
|
||||
if mode != "none":
|
||||
alpha = _drop_fragments(alpha, fragment_threshold)
|
||||
per_dir[di].append((rgb, alpha))
|
||||
if auto_crop:
|
||||
bb = _bbox(alpha)
|
||||
if bb is not None:
|
||||
boxes[di] = bb if boxes[di] is None else (
|
||||
min(boxes[di][0], bb[0]), max(boxes[di][1], bb[1]),
|
||||
min(boxes[di][2], bb[2]), max(boxes[di][3], bb[3]))
|
||||
for di in range(n_dir):
|
||||
frames = per_dir[di]
|
||||
ch, cw = frames[0][0].shape[:2]
|
||||
if auto_crop and boxes[di] is not None:
|
||||
y0, y1, x0, x1 = boxes[di]
|
||||
y0 = max(0, y0 - pad); x0 = max(0, x0 - pad)
|
||||
y1 = min(ch, y1 + pad); x1 = min(cw, x1 + pad)
|
||||
else:
|
||||
y0, y1, x0, x1 = 0, ch, 0, cw
|
||||
stack = np.empty((len(frames), y1 - y0, x1 - x0, 4), dtype=np.float32)
|
||||
for fi, (rgb, alpha) in enumerate(frames):
|
||||
stack[fi, ..., :3] = rgb[y0:y1, x0:x1]
|
||||
stack[fi, ..., 3] = alpha[y0:y1, x0:x1]
|
||||
outs.append(torch.from_numpy(stack))
|
||||
notes.append(f"{di + 1}.{names[di]} 格{cell_ids[di]} "
|
||||
f"{x1 - x0}×{y1 - y0}")
|
||||
|
||||
info = (f"输入 {B} 帧 {W}×{H} → {cols}×{rows} 网格,"
|
||||
f"空格 {sorted(empties) if empties else '无'},"
|
||||
|
||||
@@ -165,6 +165,7 @@
|
||||
1.0,
|
||||
0.05,
|
||||
true,
|
||||
true,
|
||||
8
|
||||
],
|
||||
"color": "#232",
|
||||
@@ -927,7 +928,7 @@
|
||||
"outputs": [],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"八方向行走动画 —— 完整管线\n\n【前置步骤(在本工作流之外完成)】\n 角色图 →(GPTimage2)→ 八方向静态图 →(Seedance 首尾帧)→ 循环行走视频\n 视频每一帧上都排布着 8 个朝向的角色。\n\n【本工作流做的事】\n ① VHS「Load Video」把视频转成序列帧\n · force_rate 就是帧率选择。设 0 用源视频帧率;\n 设 12 可减半出帧、素材更小,走路动画通常 8~12 帧一循环就够\n · frame_load_cap 可限制总帧数,先小批量试参数很有用\n ② 本仓库「八方向序列拆分」:切格 + 编号 + 按方向分组,一次给出 8 条序列\n ③ 每个方向各接一个 VHS「Video Combine」出透明 webm\n ④ 每个方向各接一个 SaveImage 出透明 PNG 序列帧\n\n【拆分节点的关键参数】\n · grid_cols / grid_rows / empty_cells\n 3×3 中间留空即 empty_cells=4。序号行优先、从 0 开始。\n · direction_names\n 按「跳过空格后的先后顺序」命名,默认对应下面这个排布:\n SW S SE ← 行1:面向观众\n W E ← 行2:侧面\n NW N NE ← 行3:背对观众\n 与你的素材不符就直接改这行,名字只影响标注不影响画面。\n · bg_mode / bg_threshold\n 白底转透明。只把「与画面边缘相连」的白色判为背景,\n 所以角色身上的白衬衫、白高光不会被掏空。\n 背景没扣净就调低阈值,角色边缘被啃就调高。\n · auto_crop\n 裁掉多余空白。裁剪框取该方向所有帧的并集,\n 因此整条序列尺寸一致(能合成视频),角色也不会在帧间跳动。\n\n【为什么不用连通区域拆分(本仓库的「素材拆分」节点)】\n 那个节点按包围盒排序,角色走动时位置浮动,一旦跨过排序行界方向就会错乱;\n 且每个 sprite 按各自 bbox 裁剪、尺寸不一,无法直接合成视频。\n 固定网格没有这两个问题 —— 但它更适合单张静态合图,两者各有用途。\n\n【webm 透明的关键】\n Video Combine 的 format 必须选 video/webm,且 pix_fmt 选 yuva420p。\n 注意:alpha 存放在 WebM 的独立边带里,所以用 ffprobe 看主流会显示\n yuv420p,这是正常的。播放器/引擎(走 libvpx 解码)能正确读到透明通道;\n 若要用 ffmpeg 自行验证,需显式加 -c:v libvpx-vp9 解码,\n 否则内置 vp9 解码器不会输出 alpha,会让人误以为透明丢了。\n\n【实测(97 帧 834×1112 的素材)】\n 拆分耗时约 4 秒,8 个方向各 97 帧,尺寸 172×370 ~ 206×327。"
|
||||
"八方向行走动画 —— 完整管线\n\n【前置步骤(在本工作流之外完成)】\n 角色图 →(GPTimage2)→ 八方向静态图 →(Seedance 首尾帧)→ 循环行走视频\n 视频每一帧上都排布着 8 个朝向的角色。\n\n【本工作流做的事】\n ① VHS「Load Video」把视频转成序列帧\n · force_rate 就是帧率选择。设 0 用源视频帧率;\n 设 12 可减半出帧、素材更小,走路动画通常 8~12 帧一循环就够\n · frame_load_cap 可限制总帧数,先小批量试参数很有用\n ② 本仓库「八方向序列拆分」:切格 + 编号 + 按方向分组,一次给出 8 条序列\n ③ 每个方向各接一个 VHS「Video Combine」出透明 webm\n ④ 每个方向各接一个 SaveImage 出透明 PNG 序列帧\n\n【拆分节点的关键参数】\n · grid_cols / grid_rows / empty_cells\n 3×3 中间留空即 empty_cells=4。序号行优先、从 0 开始。\n · direction_names\n 按「跳过空格后的先后顺序」命名,默认对应下面这个排布:\n SW S SE ← 行1:面向观众\n W E ← 行2:侧面\n NW N NE ← 行3:背对观众\n 与你的素材不符就直接改这行,名字只影响标注不影响画面。\n · bg_mode / bg_threshold\n 白底转透明。只把「与画面边缘相连」的白色判为背景,\n 所以角色身上的白衬衫、白高光不会被掏空。\n 背景没扣净就调低阈值,角色边缘被啃就调高。\n · expand_beyond_cell(务必开启)\n 允许角色超出格子边界。关闭时按格线严格切分,角色只要探出格线\n 就会被切断(最典型的是脚被削掉)。开启后格子只用来判定方向,\n 实际范围由角色自身的连通区域决定。\n · auto_crop\n 裁掉多余空白。裁剪框取该方向所有帧的并集,\n 因此整条序列尺寸一致(能合成视频),角色也不会在帧间跳动。\n\n【为什么不用连通区域拆分(本仓库的「素材拆分」节点)】\n 那个节点按包围盒排序,角色走动时位置浮动,一旦跨过排序行界方向就会错乱;\n 且每个 sprite 按各自 bbox 裁剪、尺寸不一,无法直接合成视频。\n 固定网格没有这两个问题 —— 但它更适合单张静态合图,两者各有用途。\n\n【webm 透明的关键】\n Video Combine 的 format 必须选 video/webm,且 pix_fmt 选 yuva420p。\n 注意:alpha 存放在 WebM 的独立边带里,所以用 ffprobe 看主流会显示\n yuv420p,这是正常的。播放器/引擎(走 libvpx 解码)能正确读到透明通道;\n 若要用 ffmpeg 自行验证,需显式加 -c:v libvpx-vp9 解码,\n 否则内置 vp9 解码器不会输出 alpha,会让人误以为透明丢了。\n\n【实测(97 帧 834×1112 的素材)】\n 拆分耗时约 4 秒,8 个方向各 97 帧,尺寸 172×370 ~ 206×327。"
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#653"
|
||||
|
||||
+9
-2
@@ -207,7 +207,10 @@ class RuiFeyNobg:
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
"image": ("IMAGE", {
|
||||
"tooltip": "待抠图的图像,支持批量(逐张推理,避免显存峰值过高)。\n"
|
||||
"RGBA 输入会自动丢弃 alpha 只取 RGB。"
|
||||
}),
|
||||
"model_name": (_list_models(), {
|
||||
"tooltip": "放在 models/nobg 下的模型目录(需含 config.json 与 "
|
||||
"model.safetensors)。\n"
|
||||
@@ -225,7 +228,11 @@ class RuiFeyNobg:
|
||||
"但 fp16 显存减半且明显更快,推荐优先用 fp16。\n"
|
||||
"保留 fp32 作默认,是为老显卡上半精度异常时有个退路。"
|
||||
}),
|
||||
"device": (["auto", "cpu"], {"default": "auto"}),
|
||||
"device": (["auto", "cpu"], {
|
||||
"default": "auto",
|
||||
"tooltip": "auto = 有显卡就用显卡。\n"
|
||||
"cpu 会慢十倍以上,仅在显存实在不够时用。"
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"alpha_threshold": ("FLOAT", {
|
||||
|
||||
+7
-2
@@ -11,9 +11,14 @@ class FlipNode:
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
"image": ("IMAGE", {
|
||||
"tooltip": "要翻转的图像。"
|
||||
}),
|
||||
"flip_direction": (["水平", "垂直"], {
|
||||
"default": "水平"
|
||||
"default": "水平",
|
||||
"tooltip": "翻转方向:\n"
|
||||
"水平 = 左右镜像(做角色朝向的反向素材常用)\n"
|
||||
"垂直 = 上下颠倒"
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
+14
-2
@@ -12,7 +12,11 @@ class SpriteSplitter:
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"图像": ("IMAGE",),
|
||||
"图像": ("IMAGE", {
|
||||
"tooltip": "待拆分的合图,需自带透明通道(背景为透明)。\n"
|
||||
"节点按 alpha 的连通区域找出各个独立素材并逐个裁出。\n"
|
||||
"白底图请先接抠图节点转成透明再进来,否则整图会被当成一块。"
|
||||
}),
|
||||
"最小面积过滤(像素数)": ("INT", {
|
||||
"default": 100,
|
||||
"min": 1,
|
||||
@@ -162,7 +166,11 @@ class SpriteSplitterRGBA:
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"图像": ("IMAGE",),
|
||||
"图像": ("IMAGE", {
|
||||
"tooltip": "待拆分的合图,需自带透明通道(背景为透明)。\n"
|
||||
"节点按 alpha 的连通区域找出各个独立素材并逐个裁出。\n"
|
||||
"白底图请先接抠图节点转成透明再进来,否则整图会被当成一块。"
|
||||
}),
|
||||
"最小面积过滤(像素数)": ("INT", {
|
||||
"default": 100, "min": 1, "max": 50000, "step": 1,
|
||||
"tooltip": "最小面积过滤。"
|
||||
@@ -173,6 +181,10 @@ class SpriteSplitterRGBA:
|
||||
}),
|
||||
"排序方式": (["从左到右-从上到下", "从上到下-从左到右", "面积从大到小", "面积从小到大"],{
|
||||
"default": "从左到右-从上到下",
|
||||
"tooltip": "输出顺序。\n"
|
||||
"⚠ 逐帧处理动画序列时慎用:素材位置一旦浮动跨过内部\n"
|
||||
"行/列分界,顺序就会在帧间改变。那种场景请改用\n"
|
||||
"「八方向序列拆分」节点(按固定网格定位,顺序恒定)。"
|
||||
}),
|
||||
"seed": ("INT", {
|
||||
"default": 0, "min": 0, "max": 0xffffffffffffffff,
|
||||
|
||||
+4
-1
@@ -14,7 +14,10 @@ class LoadImageByPathNode:
|
||||
"required": {
|
||||
"image_path": ("STRING", {
|
||||
"default": "E:\\ComfyUIModels\\input\\10\\1.png",
|
||||
"multiline": False
|
||||
"multiline": False,
|
||||
"tooltip": "图像文件的完整路径,可指向 ComfyUI 目录之外的任意位置。\n"
|
||||
"适合批量处理散落在各处的素材,省去先拷进 input 目录。\n"
|
||||
"Windows 路径直接粘贴即可,反斜杠无需转义。"
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -14,7 +14,12 @@ class LoadImageWithNameNode:
|
||||
input_dir = folder_paths.get_input_directory()
|
||||
files = [f for f in os.listdir(input_dir) if os.path.isfile(os.path.join(input_dir, f))]
|
||||
return {"required":
|
||||
{"image": (sorted(files), {"image_upload": True})},
|
||||
{"image": (sorted(files), {
|
||||
"image_upload": True,
|
||||
"tooltip": "从 input 目录选择图像,或点下方按钮上传。\n"
|
||||
"与原生加载节点的区别:额外输出不带后缀的文件名,\n"
|
||||
"便于让输出文件沿用原名,批量处理时不会张冠李戴。"
|
||||
})},
|
||||
}
|
||||
|
||||
CATEGORY = "Rui-Node🐶/文件存储与加载📁"
|
||||
|
||||
+9
-2
@@ -159,7 +159,10 @@ class RuiLucida:
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
"image": ("IMAGE", {
|
||||
"tooltip": "待抠图的图像,支持批量(逐张推理,避免显存峰值过高)。\n"
|
||||
"RGBA 输入会自动丢弃 alpha 只取 RGB。"
|
||||
}),
|
||||
"model_name": (_list_ckpts(), {
|
||||
"tooltip": "放在 models/lucida 下的权重(.safetensors)。\n"
|
||||
"未找到时首次运行会自动从 HuggingFace 下载"
|
||||
@@ -170,7 +173,11 @@ class RuiLucida:
|
||||
"tooltip": "fp16 显存减半、速度更快,实测与 fp32 输出基本一致。\n"
|
||||
"遇到黑图或异常时改回 fp32。"
|
||||
}),
|
||||
"device": (["auto", "cpu"], {"default": "auto"}),
|
||||
"device": (["auto", "cpu"], {
|
||||
"default": "auto",
|
||||
"tooltip": "auto = 有显卡就用显卡。\n"
|
||||
"cpu 会慢十倍以上,仅在显存实在不够时用。"
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"alpha_threshold": ("FLOAT", {
|
||||
|
||||
+46
-16
@@ -82,29 +82,59 @@ class MarkdownToImageNode:
|
||||
font_labels = list(scan_fonts().keys())
|
||||
default_font = DEFAULT_FONT_LABEL if DEFAULT_FONT_LABEL in font_labels \
|
||||
else font_labels[0]
|
||||
size_opt = {"default": "auto", "multiline": False}
|
||||
def _sz(desc):
|
||||
"""auto 类参数:填 auto 走自动推算,填数值则强制指定。"""
|
||||
return {"default": "auto", "multiline": False,
|
||||
"tooltip": desc + "\n填 auto 由节点自动推算,填数值则强制指定。"}
|
||||
|
||||
return {
|
||||
"required": {
|
||||
"markdown": ("STRING", {"default": _DEMO_MD, "multiline": True}),
|
||||
"markdown": ("STRING", {
|
||||
"default": _DEMO_MD, "multiline": True,
|
||||
"tooltip": "Markdown 原文。支持标题、粗斜体、删除线、行内代码、\n"
|
||||
"代码块、引用、列表、任务清单、表格、链接与彩色 Emoji。\n"
|
||||
"⚠ 别用 WAS 的「Text Multiline」喂本节点——它会把 # 开头的\n"
|
||||
"标题行当注释删掉。请用本仓库的「多行文本框(原样输出)」。"
|
||||
}),
|
||||
"size_preset": (list(_SIZE_PRESETS.keys()), {
|
||||
"default": "1080×1440 竖版 3:4",
|
||||
"tooltip": "输出尺寸预设。选 custom 时才使用下方的宽高,\n"
|
||||
"选其他预设时下方宽高会被忽略。"
|
||||
}),
|
||||
"width": ("INT", {
|
||||
"default": 1080, "min": 64, "max": 8192, "step": 8,
|
||||
"tooltip": "自定义宽度,仅在预设选 custom 时生效。"
|
||||
}),
|
||||
"height": ("INT", {
|
||||
"default": 1440, "min": 64, "max": 8192, "step": 8,
|
||||
"tooltip": "自定义高度,仅在预设选 custom 时生效。\n"
|
||||
"内容排不下时会自动缩小字号来适配,而不是裁切。"
|
||||
}),
|
||||
"font": (font_labels, {
|
||||
"default": default_font,
|
||||
"tooltip": "正文字体,列表来自 Ruinode/font 目录(ttf/otf/ttc)。\n"
|
||||
"放入新字体后刷新页面即出现。同族粗体文件(如 msyhbd)\n"
|
||||
"会自动配对用于渲染粗体,没有粗体文件时用描边模拟。"
|
||||
}),
|
||||
"theme": (list(_THEMES.keys()), {
|
||||
"default": "浅色 light",
|
||||
"tooltip": "配色主题:浅色适合分享长图,深色适合代码类内容,\n"
|
||||
"米色接近纸质阅读观感。"
|
||||
}),
|
||||
"width": ("INT", {"default": 1080, "min": 64, "max": 8192, "step": 8}),
|
||||
"height": ("INT", {"default": 1440, "min": 64, "max": 8192, "step": 8}),
|
||||
"font": (font_labels, {"default": default_font}),
|
||||
"theme": (list(_THEMES.keys()), {"default": "浅色 light"}),
|
||||
},
|
||||
"optional": {
|
||||
"body_size": ("STRING", dict(size_opt)),
|
||||
"h1_size": ("STRING", dict(size_opt)),
|
||||
"h2_size": ("STRING", dict(size_opt)),
|
||||
"h3_size": ("STRING", dict(size_opt)),
|
||||
"h4_size": ("STRING", dict(size_opt)),
|
||||
"h5_size": ("STRING", dict(size_opt)),
|
||||
"h6_size": ("STRING", dict(size_opt)),
|
||||
"letter_spacing": ("STRING", dict(size_opt)),
|
||||
"line_spacing": ("STRING", dict(size_opt)),
|
||||
"max_chars_per_line": ("STRING", dict(size_opt)),
|
||||
"body_size": ("STRING", _sz("正文字号(像素)。")),
|
||||
"h1_size": ("STRING", _sz("一级标题字号。auto 时为正文的 2.0 倍。")),
|
||||
"h2_size": ("STRING", _sz("二级标题字号。auto 时为正文的 1.5 倍。")),
|
||||
"h3_size": ("STRING", _sz("三级标题字号。auto 时为正文的 1.25 倍。")),
|
||||
"h4_size": ("STRING", _sz("四级标题字号。auto 时与正文同大。")),
|
||||
"h5_size": ("STRING", _sz("五级标题字号。auto 时为正文的 0.875 倍。")),
|
||||
"h6_size": ("STRING", _sz("六级标题字号。auto 时为正文的 0.85 倍。")),
|
||||
"letter_spacing": ("STRING", _sz("字间距(像素),可为负让字更紧凑。")),
|
||||
"line_spacing": ("STRING", _sz(
|
||||
"行距倍数,1.6 左右最接近阅读器观感;\n值越大越松散。")),
|
||||
"max_chars_per_line": ("STRING", _sz(
|
||||
"单行最多排多少字,超出即换行。\n调小可让版面更窄、更易读。")),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+15
-5
@@ -25,12 +25,19 @@ class RuiMaskPreview:
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
"mask": ("MASK",),
|
||||
"image": ("IMAGE", {
|
||||
"tooltip": "作为底图的原图。"
|
||||
}),
|
||||
"mask": ("MASK", {
|
||||
"tooltip": "要可视化的遮罩,会以彩色半透明叠在底图上。\n"
|
||||
"尺寸与底图不一致时会自动缩放对齐。"
|
||||
}),
|
||||
"mask_color": (
|
||||
["红色 / Red", "绿色 / Green", "蓝色 / Blue", "黄色 / Yellow",
|
||||
["红色 / Red", "绿色 / Green", "蓝色 / Blue", "黄色 / Yellow",
|
||||
"青色 / Cyan", "品红 / Magenta", "白色 / White"],
|
||||
{"default": "红色 / Red"}
|
||||
{"default": "红色 / Red",
|
||||
"tooltip": "叠加色。挑一个与画面主色反差大的更容易看清遮罩边界,\n"
|
||||
"例如人像多用红或青,绿植场景避开绿色。"}
|
||||
),
|
||||
},
|
||||
"optional": {
|
||||
@@ -38,7 +45,10 @@ class RuiMaskPreview:
|
||||
"default": 0.5,
|
||||
"min": 0.0,
|
||||
"max": 1.0,
|
||||
"step": 0.05
|
||||
"step": 0.05,
|
||||
"tooltip": "叠加不透明度。\n"
|
||||
"0 = 只见原图,1 = 只见纯色块。\n"
|
||||
"看边缘细节用 0.3~0.5,确认覆盖范围用 0.7 以上。"
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
+11
-3
@@ -12,14 +12,22 @@ class MaskSelector:
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"masks": ("MASK",),
|
||||
"masks": ("MASK", {
|
||||
"tooltip": "待筛选的遮罩批次(N,H,W)。单张遮罩也可以,会自动补成批次。"
|
||||
}),
|
||||
"sort_method": (["按面积排序 / By Area", "从左到右 / Left to Right", "从上到下 / Top to Bottom"], {
|
||||
"default": "按面积排序 / By Area"
|
||||
"default": "按面积排序 / By Area",
|
||||
"tooltip": "先按此规则排序,再用下面的编号取第几个。\n"
|
||||
"按面积:从大到小,取主体用它最稳\n"
|
||||
"从左到右 / 从上到下:按遮罩质心的坐标排\n"
|
||||
"空遮罩一律排到末尾。"
|
||||
}),
|
||||
"index": ("INT", {
|
||||
"default": 1,
|
||||
"min": 1,
|
||||
"step": 1
|
||||
"step": 1,
|
||||
"tooltip": "取排序后的第几个遮罩,从 1 开始。\n"
|
||||
"超出总数会自动夹到最后一个,并在 info 里标记 index_clamped。"
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
+40
-7
@@ -78,66 +78,99 @@ class OpenAINode:
|
||||
"required": {
|
||||
# 下拉框只含纯英文单词,不含 :// ,杜绝被前端吞掉
|
||||
"protocol": (["https", "http"], {
|
||||
"default": "https"
|
||||
"default": "https",
|
||||
"tooltip": "接口协议。之所以单独做成下拉而不写进地址栏:\n"
|
||||
"ComfyUI 前端会吞掉文本框里的 \"://\" 片段,\n"
|
||||
"协议只能由后端拼接。"
|
||||
}),
|
||||
# 默认值不含任何协议前缀,杜绝被前端吞掉
|
||||
"api_url": ("STRING", {
|
||||
"default": "api.openai.com/v1/chat/completions",
|
||||
"multiline": False,
|
||||
"tooltip": "接口地址,**不要带 http:// 或 https://**(协议见上方下拉)。\n"
|
||||
"只填域名和路径,例如 api.openai.com/v1/chat/completions。\n"
|
||||
"第三方中转填对应的域名即可。"
|
||||
}),
|
||||
"api_key": ("STRING", {
|
||||
"default": "",
|
||||
"multiline": False,
|
||||
"tooltip": "API 密钥。\n"
|
||||
"⚠ 工作流会连同此值一起保存,分享 json 前记得清空。"
|
||||
}),
|
||||
"model": ("STRING", {
|
||||
"default": "gpt-4o",
|
||||
"multiline": False,
|
||||
"tooltip": "模型名,按服务商文档填写。\n"
|
||||
"要传图就必须选支持视觉的型号,否则图会被忽略或直接报错。"
|
||||
}),
|
||||
"system_prompt": ("STRING", {
|
||||
"default": "You are a helpful assistant.",
|
||||
"multiline": True,
|
||||
"tooltip": "系统提示词:设定模型的角色与总体行为准则。\n"
|
||||
"输出格式要求(如「只返回 JSON」)写在这里比写在用户\n"
|
||||
"提示词里更稳定。"
|
||||
}),
|
||||
"user_prompt": ("STRING", {
|
||||
"default": "",
|
||||
"multiline": True,
|
||||
"tooltip": "用户提示词:这一次具体要模型做什么。\n"
|
||||
"接了图像时,在这里描述针对图像的任务。"
|
||||
}),
|
||||
"seed": ("INT", {
|
||||
"default": 0,
|
||||
"min": 0,
|
||||
"max": 0xffffffffffffffff,
|
||||
"tooltip": "随机种子。多数服务商并不真正支持复现,\n"
|
||||
"这里主要用于强制节点重新执行(改了它就不会走缓存)。"
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"image_1": ("IMAGE",),
|
||||
"image_2": ("IMAGE",),
|
||||
"image_3": ("IMAGE",),
|
||||
"image_4": ("IMAGE",),
|
||||
"image_5": ("IMAGE",),
|
||||
"image_6": ("IMAGE",),
|
||||
"image_1": ("IMAGE", {
|
||||
"tooltip": "要一并发给模型的图像 1(需模型支持视觉)。\n"
|
||||
"会按下方的最大边长压缩后转 base64 提交。"
|
||||
}),
|
||||
"image_2": ("IMAGE", {"tooltip": "图像 2。"}),
|
||||
"image_3": ("IMAGE", {"tooltip": "图像 3。"}),
|
||||
"image_4": ("IMAGE", {"tooltip": "图像 4。"}),
|
||||
"image_5": ("IMAGE", {"tooltip": "图像 5。"}),
|
||||
"image_6": ("IMAGE", {"tooltip": "图像 6。图越多越贵、越慢。"}),
|
||||
"temperature": ("FLOAT", {
|
||||
"default": 0.3,
|
||||
"min": 0.0,
|
||||
"max": 2.0,
|
||||
"step": 0.1,
|
||||
"tooltip": "采样温度:越低越稳定保守,越高越发散。\n"
|
||||
"要结构化/可解析的输出用 0~0.3;\n"
|
||||
"要创意文案用 0.7~1.0。超过 1.2 常出现胡言乱语。"
|
||||
}),
|
||||
"max_tokens": ("INT", {
|
||||
"default": 500,
|
||||
"min": 1,
|
||||
"max": 8192,
|
||||
"tooltip": "回复的最大长度上限。\n"
|
||||
"设小了会把回答从中间截断,长文任务记得调大。"
|
||||
}),
|
||||
"detail": (["low", "high", "auto"], {
|
||||
"default": "auto",
|
||||
"tooltip": "图像细节级别(OpenAI 视觉参数):\n"
|
||||
"low 便宜快速,只看大致内容;\n"
|
||||
"high 会切块细看,认小字/细节更准但更贵;\n"
|
||||
"auto 由服务端决定。"
|
||||
}),
|
||||
"image_max_size": ("INT", {
|
||||
"default": 1024,
|
||||
"min": 256,
|
||||
"max": 4096,
|
||||
"step": 64,
|
||||
"tooltip": "上传前把图缩放到的最大边长。\n"
|
||||
"调小可显著省钱提速,但小字与细节会看不清。"
|
||||
}),
|
||||
# 代理地址也不带协议前缀,只填 IP:端口 即可
|
||||
"proxy_url": ("STRING", {
|
||||
"default": "",
|
||||
"multiline": False,
|
||||
"tooltip": "HTTP 代理,**同样不要带协议前缀**,只填 IP:端口,\n"
|
||||
"例如 127.0.0.1:7890。留空表示直连。"
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -15,7 +15,11 @@ class PageNarrationRemoverNode:
|
||||
"required": {
|
||||
"input_text": ("STRING", {
|
||||
"multiline": True,
|
||||
"default": ""
|
||||
"default": "",
|
||||
"tooltip": "原始文本(多行)。节点会删掉形如\n"
|
||||
" 页面旁白:\"……\"\n"
|
||||
"这样单独成行的旁白,其余内容原样保留。\n"
|
||||
"只处理独占一行的旁白,行内夹带的不会被误删。"
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
+10
-2
@@ -66,7 +66,10 @@ class RuiPixelate:
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
"image": ("IMAGE", {
|
||||
"tooltip": "待像素化的图像。批量输入时若各图比例不同,\n"
|
||||
"会统一到首张的输出尺寸(ComfyUI 的 IMAGE 必须同形状)。"
|
||||
}),
|
||||
"mode": (_MODES, {
|
||||
"default": "按目标宽度",
|
||||
"tooltip": "按目标宽度:普通图转像素画,直接给输出宽度\n"
|
||||
@@ -132,7 +135,12 @@ class RuiPixelate:
|
||||
"tooltip": "遮罩二值化阈值,高于它算不透明。\n"
|
||||
"设为 0 则保留灰度遮罩(不二值化)。"
|
||||
}),
|
||||
"seed": ("INT", {"default": 0, "min": 0, "max": 0xFFFFFFFF}),
|
||||
"seed": ("INT", {
|
||||
"default": 0, "min": 0, "max": 0xFFFFFFFF,
|
||||
"tooltip": "随机种子。影响 k-means 调色板的初始化与随机噪声抖动;\n"
|
||||
"同一张图换种子会得到略有差异的配色,可多试几个挑顺眼的。\n"
|
||||
"固定调色板与 Bayer 抖动不受它影响。"
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+33
-10
@@ -16,37 +16,60 @@ class QwenEditNode:
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image1": ("IMAGE",),
|
||||
"image2": ("IMAGE",),
|
||||
"image3": ("IMAGE",),
|
||||
"image4": ("IMAGE",),
|
||||
"image1": ("IMAGE", {
|
||||
"tooltip": "参考图 1(主参考)。控制模式决定它以什么方式影响生成,\n"
|
||||
"例如 reference 取整体风格、pose 取人物姿态。"
|
||||
}),
|
||||
"image2": ("IMAGE", {
|
||||
"tooltip": "参考图 2。多张参考会一并提交,用于综合约束生成结果。"
|
||||
}),
|
||||
"image3": ("IMAGE", {
|
||||
"tooltip": "参考图 3。"
|
||||
}),
|
||||
"image4": ("IMAGE", {
|
||||
"tooltip": "参考图 4。"
|
||||
}),
|
||||
"api_key": ("STRING", {
|
||||
"default": "",
|
||||
"multiline": False
|
||||
"multiline": False,
|
||||
"tooltip": "阿里云百炼(DashScope)的 API Key。\n"
|
||||
"⚠ 工作流会连同此值一起保存,分享 json 前记得清空。"
|
||||
}),
|
||||
"base_url": ("STRING", {
|
||||
"default": "https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image-generation/generation",
|
||||
"multiline": False
|
||||
"multiline": False,
|
||||
"tooltip": "接口地址,一般不用改。\n"
|
||||
"走代理或私有网关时替换成对应地址。"
|
||||
}),
|
||||
"seed": ("INT", {
|
||||
"default": -1,
|
||||
"min": -1,
|
||||
"max": 2147483647
|
||||
"max": 2147483647,
|
||||
"tooltip": "随机种子。-1 表示每次随机;\n"
|
||||
"填固定值可复现同一结果,便于对比参数改动的影响。"
|
||||
}),
|
||||
"control_mode": (["reference", "sketch", "scribble", "pose", "canny", "depth", "hed", "mlsd", "normal", "seg"], {
|
||||
"default": "reference"
|
||||
"default": "reference",
|
||||
"tooltip": "参考图的约束方式:\n"
|
||||
"reference 整体风格参考(最常用)\n"
|
||||
"pose 取人物姿态 / depth 取空间深度 / seg 取区域分割\n"
|
||||
"canny·hed·mlsd·scribble·sketch 取不同粗细的线稿\n"
|
||||
"normal 取法线朝向。约束越强,构图越贴近参考图。"
|
||||
}),
|
||||
"width": ("INT", {
|
||||
"default": 1024,
|
||||
"min": 512,
|
||||
"max": 2048,
|
||||
"step": 8
|
||||
"step": 8,
|
||||
"tooltip": "输出宽度。与高度共同决定画幅比例,\n"
|
||||
"比例与参考图差异过大时构图容易变形。"
|
||||
}),
|
||||
"height": ("INT", {
|
||||
"default": 1024,
|
||||
"min": 512,
|
||||
"max": 2048,
|
||||
"step": 8
|
||||
"step": 8,
|
||||
"tooltip": "输出高度。"
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
+8
-2
@@ -11,12 +11,18 @@ class SaturationNode:
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
"image": ("IMAGE", {
|
||||
"tooltip": "要调整饱和度的图像。"
|
||||
}),
|
||||
"saturation": ("FLOAT", {
|
||||
"default": 1.0,
|
||||
"min": 0.0,
|
||||
"max": 5.0,
|
||||
"step": 0.1
|
||||
"step": 0.1,
|
||||
"tooltip": "饱和度系数:\n"
|
||||
"0.0 = 完全去色(黑白)\n"
|
||||
"1.0 = 保持原样\n"
|
||||
"1.0~2.0 = 色彩逐渐浓郁,超过 2.0 容易溢出失真"
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
+19
-4
@@ -168,7 +168,11 @@ class RuiSDMatteLoader:
|
||||
"tooltip": "官方测试配置为 fp32(amp.enabled=False)。\n"
|
||||
"fp16 省显存但 SD 2.1 的 VAE 在半精度下容易溢出,可能出现黑图或噪点。"
|
||||
}),
|
||||
"device": (["auto", "cpu"], {"default": "auto"}),
|
||||
"device": (["auto", "cpu"], {
|
||||
"default": "auto",
|
||||
"tooltip": "auto = 有显卡就用显卡。\n"
|
||||
"SDMatte 体量大,cpu 推理会慢到不实用,仅作兜底。"
|
||||
}),
|
||||
"attention_slicing": ("BOOLEAN", {
|
||||
"default": True,
|
||||
"tooltip": "分片计算注意力。1024 分辨率下显存峰值从约 15.5GB 降到 9.1GB,\n"
|
||||
@@ -208,8 +212,14 @@ class RuiSDMatte:
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"sdmatte_model": ("SDMATTE_MODEL",),
|
||||
"image": ("IMAGE",),
|
||||
"sdmatte_model": ("SDMATTE_MODEL", {
|
||||
"tooltip": "由「SDMatte 加载器」输出的模型。\n"
|
||||
"加载器有缓存,多个抠图节点可共用同一个加载器。"
|
||||
}),
|
||||
"image": ("IMAGE", {
|
||||
"tooltip": "待抠图的原图。RGBA 输入会自动丢弃 alpha 只取 RGB\n"
|
||||
"(VAE 编码器只收 3 通道,多出的 alpha 不能当颜色喂进去)。"
|
||||
}),
|
||||
"mask": ("MASK", {
|
||||
"tooltip": "指示要抠哪个目标的提示掩码,不必精确,粗略覆盖主体即可。"
|
||||
}),
|
||||
@@ -250,7 +260,12 @@ class RuiSDMatte:
|
||||
"再逐像素取最大值合成提示图 —— 即每个点的影响半径。\n"
|
||||
"官方训练用 25,测试期用 25+10=35,故默认 35。"
|
||||
}),
|
||||
"seed": ("INT", {"default": 0, "min": 0, "max": 0xFFFFFFFF}),
|
||||
"seed": ("INT", {
|
||||
"default": 0, "min": 0, "max": 0xFFFFFFFF,
|
||||
"tooltip": "随机种子,仅在 prompt_type=point_mask 时真正起作用\n"
|
||||
"(决定在提示区域里随机取哪 10 个点)。\n"
|
||||
"其余提示类型下改它不会改变结果。"
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ class ShotSplitterNode:
|
||||
"required": {
|
||||
"input_text": ("STRING", {
|
||||
"multiline": True,
|
||||
"default": ""
|
||||
"default": "",
|
||||
"tooltip": "多分镜脚本原文。节点会识别「镜头1 / 分镜2 / Shot 3」\n"
|
||||
"这类编号标记,把整段脚本拆成一条条独立的分镜描述。"
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
@@ -20,12 +22,16 @@ class ShotSplitterNode:
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"step": 1,
|
||||
"tooltip": "从第几号镜头开始取,0 表示从头开始。\n"
|
||||
"用于跳过前面已经出过图的镜头。"
|
||||
}),
|
||||
"shot_count": ("INT", {
|
||||
"default": 0,
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"step": 1,
|
||||
"tooltip": "取多少个镜头,0 表示一直取到结尾。\n"
|
||||
"与上面的起始号配合,可以分批处理长脚本。"
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ class RuiTextBoxNode:
|
||||
"multiline": True,
|
||||
# 关闭动态提示词处理,杜绝 {a|b}、通配符等被前端改写
|
||||
"dynamicPrompts": False,
|
||||
"tooltip": "多行文本,一字不动地原样输出。\n"
|
||||
"不删注释行、不做动态提示词/通配符/token 替换。\n\n"
|
||||
"用来替代 WAS 的「Text Multiline」——那个节点会把\n"
|
||||
"「#」开头的行当注释删掉,喂 Markdown 时标题会凭空消失。\n"
|
||||
"承载 Markdown、代码等格式敏感的文本请用本节点。"
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
+11
-5
@@ -12,25 +12,31 @@ class TextListNode:
|
||||
"required": {
|
||||
"text1": ("STRING", {
|
||||
"multiline": True,
|
||||
"default": ""
|
||||
"default": "",
|
||||
"tooltip": "第 1 段文本。列表按 text1~text5 的顺序组织,\n"
|
||||
"空白段会被自动跳过,不会在列表里留空位。"
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"text2": ("STRING", {
|
||||
"multiline": True,
|
||||
"default": ""
|
||||
"default": "",
|
||||
"tooltip": "第 2 段文本,留空则跳过。"
|
||||
}),
|
||||
"text3": ("STRING", {
|
||||
"multiline": True,
|
||||
"default": ""
|
||||
"default": "",
|
||||
"tooltip": "第 3 段文本,留空则跳过。"
|
||||
}),
|
||||
"text4": ("STRING", {
|
||||
"multiline": True,
|
||||
"default": ""
|
||||
"default": "",
|
||||
"tooltip": "第 4 段文本,留空则跳过。"
|
||||
}),
|
||||
"text5": ("STRING", {
|
||||
"multiline": True,
|
||||
"default": ""
|
||||
"default": "",
|
||||
"tooltip": "第 5 段文本,留空则跳过。"
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,10 @@ class UTF8ConverterNode:
|
||||
"input_text": ("STRING", {
|
||||
"multiline": True,
|
||||
"default": "",
|
||||
"placeholder": "输入文本 / Input Text"
|
||||
"placeholder": "输入文本 / Input Text",
|
||||
"tooltip": "待转码的文本。用于把从各处复制来的乱码文本\n"
|
||||
"(GBK/UTF-16 等被误读的内容)修正为正常 UTF-8。\n"
|
||||
"若下方填了文件路径,则以文件内容为准,本框会被忽略。"
|
||||
}),
|
||||
"remove_emoji": ("BOOLEAN", {
|
||||
"default": True,
|
||||
@@ -93,7 +96,10 @@ class UTF8ConverterNode:
|
||||
"input_file": ("STRING", {
|
||||
"multiline": False,
|
||||
"default": "",
|
||||
"placeholder": "文件路径 / File Path (优先读取 / Overrides input_text)"
|
||||
"placeholder": "文件路径 / File Path (优先读取 / Overrides input_text)",
|
||||
"tooltip": "文本文件路径。填了它就优先读文件,忽略上面的输入框。\n"
|
||||
"会依次尝试 UTF-8 → UTF-16(带BOM) → GB18030 解码,\n"
|
||||
"都失败则忽略非法字节强行读出,尽量不让整个文件报废。"
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
+32
-3
@@ -89,28 +89,57 @@ class ImageWatermarkNode:
|
||||
else (font_labels[0] if font_labels else "")
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
"image": ("IMAGE", {
|
||||
"tooltip": "要打水印的图像,支持批量,每张都会独立处理。"
|
||||
}),
|
||||
"text": ("STRING", {
|
||||
"default": "仅供参考 / SAMPLE",
|
||||
"multiline": True,
|
||||
"tooltip": "水印文案,支持多行(直接在框里换行)。\n"
|
||||
"多行会作为一个整体单元平铺,行内间距按字号的 25% 自动计算。"
|
||||
}),
|
||||
"font": (font_labels, {
|
||||
"default": default_font,
|
||||
"tooltip": "字体,列表来自 Ruinode/font 目录,与 Markdown 转图片节点共用。\n"
|
||||
"放入新的 ttf/otf/ttc 后刷新页面即可出现。\n"
|
||||
"列表里没有的字体会自动回退,不会报错。"
|
||||
}),
|
||||
"font": (font_labels, {"default": default_font}),
|
||||
"font_size": ("INT", {
|
||||
"default": 48, "min": 8, "max": 500, "step": 1,
|
||||
"tooltip": "文字大小(像素)。它同时是密度的基准——\n"
|
||||
"改字号时水印疏密会等比缩放,视觉观感保持稳定。"
|
||||
}),
|
||||
"angle": ("FLOAT", {
|
||||
"default": 30.0, "min": -180.0, "max": 180.0, "step": 1.0,
|
||||
"tooltip": "水印整体旋转角度(度)。\n"
|
||||
"实现上先在超过对角线的画布上平铺、整体旋转后再从中心裁切,\n"
|
||||
"所以任何角度下四角都不会露白。"
|
||||
}),
|
||||
"density": ("FLOAT", {
|
||||
"default": 1.0, "min": 0.1, "max": 5.0, "step": 0.05,
|
||||
"tooltip": "水印密度,越大越密。控制的是水印之间的空隙:\n"
|
||||
"空隙 = 字号 × 2 ÷ 密度。\n"
|
||||
"0.4 左右 = 稀疏点缀;1.0 = 默认;\n"
|
||||
"2.5 以上 = 密集防盗(建议同时把透明度降到 20~30)"
|
||||
}),
|
||||
"letter_spacing": ("INT", {
|
||||
"default": 0, "min": -20, "max": 200, "step": 1,
|
||||
"tooltip": "字间距:单条文案内相邻字符的额外间距(像素)。\n"
|
||||
"逐字符绘制实现,可为负值让字挤在一起。"
|
||||
}),
|
||||
"opacity": ("FLOAT", {
|
||||
"default": 35.0, "min": 0.0, "max": 100.0, "step": 1.0,
|
||||
"tooltip": "水印透明程度:0 = 完全透明(原样返回,不做任何计算),\n"
|
||||
"100 = 完全不透明。\n"
|
||||
"防盗建议 25~40:看得清但不影响读图。"
|
||||
}),
|
||||
"color": ("STRING", {
|
||||
"default": "#FFFFFF", "multiline": False,
|
||||
"tooltip": "水印颜色,四种写法都支持:\n"
|
||||
"#FFFFFF / #FFF / 255,255,255 / white\n"
|
||||
"认不出的写法会回退成灰色,不会报错。\n"
|
||||
"深色图用白色,浅色图用黑或深灰,彩色图用黄色最醒目。"
|
||||
}),
|
||||
"color": ("STRING", {"default": "#FFFFFF", "multiline": False}),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+41
-6
@@ -133,24 +133,35 @@ class ZenMuxNode:
|
||||
"api_key": ("STRING", {
|
||||
"default": "",
|
||||
"multiline": False,
|
||||
"tooltip": "ZenMux 的 API Key。\n"
|
||||
"⚠ 工作流会连同此值一起保存,分享 json 前记得清空。"
|
||||
}),
|
||||
# 全量模型标签(含价格),已按厂商排序聚类;
|
||||
# 下拉搜索框输入厂商前缀(如 "qwen/")即可过滤。
|
||||
"model": (model_labels, {
|
||||
"default": default_label,
|
||||
"tooltip": "模型,标签里直接带了输入/输出单价。\n"
|
||||
"列表按厂商聚类排序——在下拉的搜索框输入厂商前缀\n"
|
||||
"(如 qwen/ 、anthropic/ )即可快速过滤。\n"
|
||||
"要传图请选支持视觉的型号,否则图会被忽略。"
|
||||
}),
|
||||
"system_prompt": ("STRING", {
|
||||
"default": "You are a helpful assistant.",
|
||||
"multiline": True,
|
||||
"tooltip": "系统提示词:设定模型的角色与总体行为准则。\n"
|
||||
"输出格式要求(如「只返回 JSON」)写在这里最稳定。"
|
||||
}),
|
||||
"user_prompt": ("STRING", {
|
||||
"default": "",
|
||||
"multiline": True,
|
||||
"tooltip": "用户提示词:这一次具体要模型做什么。"
|
||||
}),
|
||||
"seed": ("INT", {
|
||||
"default": 0,
|
||||
"min": 0,
|
||||
"max": 0xffffffffffffffff,
|
||||
"tooltip": "随机种子。多数模型并不真正支持复现,\n"
|
||||
"这里主要用于强制节点重新执行(改了它就不会走缓存)。"
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
@@ -159,42 +170,63 @@ class ZenMuxNode:
|
||||
"min": 0.0,
|
||||
"max": 2.0,
|
||||
"step": 0.1,
|
||||
"tooltip": "采样温度:越低越稳定保守,越高越发散。\n"
|
||||
"结构化输出用 0~0.3,创意文案用 0.7~1.0。\n"
|
||||
"部分新模型已弃用该参数,节点会自动重试并剔除它。"
|
||||
}),
|
||||
"top_p": ("FLOAT", {
|
||||
"default": 1.0,
|
||||
"min": 0.0,
|
||||
"max": 1.0,
|
||||
"step": 0.05,
|
||||
"tooltip": "核采样:只在累计概率前 top_p 的词里挑。\n"
|
||||
"与温度作用重叠,一般固定 1.0 只调温度,别两个一起动。"
|
||||
}),
|
||||
"max_tokens": ("INT", {
|
||||
"default": 1024,
|
||||
"min": 1,
|
||||
"max": 200000,
|
||||
"tooltip": "回复的最大长度上限。设小了会把回答从中间截断。\n"
|
||||
"注意它同时是费用上限的重要因素。"
|
||||
}),
|
||||
# 多模态图像输入(模型需支持 image 输入才有意义)
|
||||
"image_1": ("IMAGE",),
|
||||
"image_2": ("IMAGE",),
|
||||
"image_3": ("IMAGE",),
|
||||
"image_4": ("IMAGE",),
|
||||
"image_5": ("IMAGE",),
|
||||
"image_6": ("IMAGE",),
|
||||
"image_1": ("IMAGE", {
|
||||
"tooltip": "要一并发给模型的图像 1(需模型支持视觉)。\n"
|
||||
"会按下方最大边长压缩后转 base64 提交。"
|
||||
}),
|
||||
"image_2": ("IMAGE", {"tooltip": "图像 2。"}),
|
||||
"image_3": ("IMAGE", {"tooltip": "图像 3。"}),
|
||||
"image_4": ("IMAGE", {"tooltip": "图像 4。"}),
|
||||
"image_5": ("IMAGE", {"tooltip": "图像 5。"}),
|
||||
"image_6": ("IMAGE", {"tooltip": "图像 6。图越多越贵、越慢。"}),
|
||||
"detail": (["auto", "low", "high"], {
|
||||
"default": "auto",
|
||||
"tooltip": "图像细节级别:\n"
|
||||
"low 便宜快速,只看大致内容;\n"
|
||||
"high 切块细看,认小字/细节更准但更贵;\n"
|
||||
"auto 由服务端决定。"
|
||||
}),
|
||||
"image_max_size": ("INT", {
|
||||
"default": 1024,
|
||||
"min": 256,
|
||||
"max": 4096,
|
||||
"step": 64,
|
||||
"tooltip": "上传前把图缩放到的最大边长。\n"
|
||||
"调小可显著省钱提速,但小字与细节会看不清。"
|
||||
}),
|
||||
# 高级:一般无需改动,留空即用官方地址(无需写 https://,会自动补全)
|
||||
"base_url": ("STRING", {
|
||||
"default": DEFAULT_BASE_URL_INPUT,
|
||||
"multiline": False,
|
||||
"tooltip": "接口地址,一般不用改。\n"
|
||||
"**不要写 https://** —— ComfyUI 前端会吞掉 \"://\",\n"
|
||||
"协议由后端自动补全,这里只填域名和路径。"
|
||||
}),
|
||||
"proxy_url": ("STRING", {
|
||||
"default": "",
|
||||
"multiline": False,
|
||||
"tooltip": "HTTP 代理,同样不要带协议前缀,只填 IP:端口,\n"
|
||||
"例如 127.0.0.1:7890。留空表示直连。"
|
||||
}),
|
||||
# usage_stats 里人民币换算用的汇率,可按当日牌价自行调整
|
||||
"usd_to_cny": ("FLOAT", {
|
||||
@@ -202,6 +234,9 @@ class ZenMuxNode:
|
||||
"min": 0.1,
|
||||
"max": 100.0,
|
||||
"step": 0.01,
|
||||
"tooltip": "美元兑人民币汇率,仅用于把 usage_stats 输出里的\n"
|
||||
"费用换算成人民币显示,不影响实际计费。\n"
|
||||
"可按当日牌价自行调整。"
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user