Ways: new scene, same character
change_scene cuts the character out of a handed picture (inspyrenet-rembg), inverts it and redraws only the rest at denoise 1.0 from the prompt's new scene; GrowMask lets 6 px of the edge be redrawn for the seam. Tried on an RTX 4050 6 GB with SDXL (Illustrious) 832x1216: about 30 s, the character kept, the forest replaced by a night street. A picture handed to a block may be written "name.png [output]" as Load Image shows it. Two block descriptions are shorter so begin_task stays under 4000 characters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d1d53cfc63
commit
d95b2b309f
@@ -2,6 +2,9 @@
|
||||
|
||||
## v1.63.0 — unreleased
|
||||
|
||||
- 新做法 **换场景·人物不变**:你递给 AI 一张图,AMB 自动抠出人物(inspyrenet-rembg),只重画人物以外的地方,AI 在提示词里写新场景;人物边缘留 6 像素一起重画,接缝更自然。实测 RTX 4050 6GB、SDXL 832×1216 约 30 秒。人物身上的光还是原图的光,换到光线差别很大的场景时看得出来(以后可以加重新打光)。AI 递给做法的图也认 `名字.png [output]` 这种写法了。
|
||||
- New way **New scene, same character**: from a picture handed to the AI, the character is cut out (inspyrenet-rembg) and only the rest is drawn anew from the prompt's new scene; 6 px of its edge are redrawn too for the seam. About 30 s for SDXL 832×1216 on an RTX 4050 6 GB. The character keeps the old picture's light, which shows in a very differently lit scene (relighting may come later). A picture handed to a block may also be written `name.png [output]`.
|
||||
|
||||
- AI 有了现成的做法可以照着用(参考做法):从擅长这些活的工作流里提炼出来的几块节点,AI 说一声用哪块,AMB 就在画布上搭好、接进你的工作流里,一次调用,不用 AI 一个个节点地搭。AI 开工时会收到这份清单,每块一行。
|
||||
- **局部重绘·裁切缝合**:把圈出的地方连同周围一圈一起裁出来,放大到 1024 重画,再缝回原图,别处一点不动。AMB 顺手把采样强度调到 0.75,并提醒 AI 把提示词改成只写这块地方(比如“一只手,五根手指”),不然它会把整张图的内容(比如一整个人)画进这一小块里。需要节点包 ComfyUI-Inpaint-CropAndStitch。
|
||||
- **局部重绘(官方节点)**:没装上面那个包时用它,只用 ComfyUI 自带的节点。
|
||||
|
||||
@@ -149,6 +149,8 @@ def to_input(image):
|
||||
from .mcp_tools import _resolve_folder_image
|
||||
|
||||
rel = str(image or "").replace("\\", "/").strip("/")
|
||||
if rel.endswith(" [output]"): # ComfyUI's mark for an output picture, as Load Image shows it
|
||||
rel = rel[: -len(" [output]")]
|
||||
try:
|
||||
return _resolve_folder_image(rel, "input")[0]
|
||||
except ToolError:
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"job": "repaint",
|
||||
"rank": 4,
|
||||
"short": "new background",
|
||||
"title": {
|
||||
"zh": "换场景·人物不变",
|
||||
"en": "New scene, same character"
|
||||
},
|
||||
"about": {
|
||||
"zh": "你递给 AI 一张图,AMB 自动抠出人物,只重画人物以外的地方:AI 在提示词里写新场景,人物原样留下。人物边缘留几像素一起重画,让新背景和人物接得上。",
|
||||
"en": "From a picture you hand the AI, the character is cut out automatically and everything else is drawn anew: the prompt says the new scene, the character stays as it was. A few pixels of its edge are redrawn too, so it sits in the new scene."
|
||||
},
|
||||
"source": {
|
||||
"zh": "常见的“抠图换背景”做法:inspyrenet-rembg 抠人物,反选成背景,用 ComfyUI 自带的局部重绘节点只重画背景",
|
||||
"en": "The common cut-out-and-replace-the-background way: inspyrenet-rembg finds the character, its inverse is the background, ComfyUI's own inpainting nodes redraw only that"
|
||||
},
|
||||
"packs": {
|
||||
"InspyrenetRembg": "comfyui-inspyrenet-rembg"
|
||||
},
|
||||
"takes": "picture",
|
||||
"nodes": {
|
||||
"picture": {
|
||||
"class_type": "LoadImage",
|
||||
"inputs": {
|
||||
"image": "$image"
|
||||
}
|
||||
},
|
||||
"cut": {
|
||||
"class_type": "InspyrenetRembg",
|
||||
"inputs": {
|
||||
"image": [
|
||||
"picture",
|
||||
0
|
||||
],
|
||||
"torchscript_jit": "default"
|
||||
}
|
||||
},
|
||||
"background": {
|
||||
"class_type": "InvertMask",
|
||||
"inputs": {
|
||||
"mask": [
|
||||
"cut",
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
"edge": {
|
||||
"class_type": "GrowMask",
|
||||
"inputs": {
|
||||
"mask": [
|
||||
"background",
|
||||
0
|
||||
],
|
||||
"expand": 6,
|
||||
"tapered_corners": true
|
||||
}
|
||||
},
|
||||
"soft": {
|
||||
"class_type": "DifferentialDiffusion",
|
||||
"inputs": {
|
||||
"model": [
|
||||
"$sampler.model",
|
||||
"*"
|
||||
]
|
||||
},
|
||||
"wire_to": "$sampler"
|
||||
},
|
||||
"encode": {
|
||||
"class_type": "VAEEncode",
|
||||
"inputs": {
|
||||
"pixels": [
|
||||
"picture",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"$decode.vae",
|
||||
"*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"area": {
|
||||
"class_type": "SetLatentNoiseMask",
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"encode",
|
||||
0
|
||||
],
|
||||
"mask": [
|
||||
"edge",
|
||||
0
|
||||
]
|
||||
},
|
||||
"wire_to": "$sampler"
|
||||
},
|
||||
"look": {
|
||||
"class_type": "PreviewImage",
|
||||
"inputs": {
|
||||
"images": [
|
||||
"cut",
|
||||
0
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"roles": {
|
||||
"sampler": {
|
||||
"denoise": 1.0
|
||||
}
|
||||
},
|
||||
"after": "Write the new scene in the prompt and keep the character's own words (who, hair, clothes) so its edge fits, then run_workflow. The picture's size is the drawing's: the empty latent is no longer used. The kept character (cut out) is among the run's previews: if part of it is missing or the old background clings to it, say so; a halo at its edge: raise the GrowMask expand (6) a little.",
|
||||
"notes": "Denoise 1.0: the background is drawn anew, not changed. GrowMask lets the background reach 6 px into the character so the seam is redrawn.",
|
||||
"models": [],
|
||||
"tested": {
|
||||
"gpu": "RTX 4050 Laptop",
|
||||
"vram_gb": 6,
|
||||
"date": "2026-10-28",
|
||||
"runs": [
|
||||
{
|
||||
"model": "SDXL (Illustrious)",
|
||||
"size": "832×1216",
|
||||
"seconds": 30
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"job": "upscale",
|
||||
"rank": 2,
|
||||
"short": "1.25×, held by a tile ControlNet, more detail",
|
||||
"short": "1.25×, tile-held, more detail",
|
||||
"title": {
|
||||
"zh": "平铺放大",
|
||||
"en": "Upscale held by tile"
|
||||
|
||||
@@ -57,7 +57,7 @@ class BlockTests(unittest.TestCase):
|
||||
self.assertLess(len(" ".join(everything.values())), 900, "small: it goes with begin_task")
|
||||
with mock.patch.object(reference_blocks, "DIRECTORY_CHARS", 200):
|
||||
names = reference_blocks.directory(EVERYTHING)
|
||||
self.assertEqual(names[reference_blocks.JOBS["repaint"]], "inpaint_crop_stitch, inpaint_lanpaint, inpaint_basic",
|
||||
self.assertEqual(names[reference_blocks.JOBS["repaint"]], "inpaint_crop_stitch, inpaint_lanpaint, inpaint_basic, change_scene",
|
||||
"too many to say each: the names alone")
|
||||
|
||||
def test_a_block_turned_off_is_not_offered_and_cannot_be_built(self):
|
||||
@@ -288,6 +288,7 @@ class ReferencePictureTests(unittest.TestCase):
|
||||
mock.patch.object(folders, "get_input_directory", return_value=input_dir):
|
||||
name = ai_pictures.to_input("ai_inbox/ref.png")
|
||||
self.assertEqual(ai_pictures.to_input("ai_inbox\\ref.png"), name, "the same picture, the same file")
|
||||
self.assertEqual(ai_pictures.to_input("ai_inbox/ref.png [output]"), name, "as Load Image names an output picture")
|
||||
self.assertEqual(ai_pictures.to_input("mine.png"), "mine.png")
|
||||
with self.assertRaises(ToolError):
|
||||
ai_pictures.to_input("ai_inbox/gone.png")
|
||||
|
||||
Reference in New Issue
Block a user