Enlarge a picture for fixing hands by its size: about 4 MP, 1x to 2x

1.5x left the Codex test picture's hand better but still soft; 2x gave
sharper fingers in the same seeds (about 105 s instead of 75 s on a 6 GB
card). The fix-hands way now enlarges to about 4.2 megapixels, never
smaller, at most 2x: reference_blocks.enlargement reads the picture's
size (add_nodes passes picture_size of its input copy). Tried through
AMB on an isolated ComfyUI: 2547x1656, no memory trouble, 2 clean hands
of 4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DemonGatanjieu
2026-10-29 16:03:29 +08:00
co-authored by Claude Opus 5.5
parent b3f40131cf
commit 83dc2aed2f
6 changed files with 38 additions and 15 deletions
+2 -2
View File
@@ -5,8 +5,8 @@
- 跑图前的尺寸提醒放宽一档:6GB 显卡采样到约 420 万像素才提醒(以前 210 万),12GB 约 840 万。今天在 6GB 的笔记本显卡上实测,400 万像素一次约 100 秒,并不吃紧;以前的门槛会让 AI 动不动就问你要不要停。解码大图的提醒不变。
- The size warning before a run is less eager: on a 6 GB card from about 4.2 megapixels (2.1 before), 8.4 on 12 GB. A 6 GB laptop card sampled 4 megapixels in about 100 s today; the old line had the AI ask you to stop runs that were fine. The warning for decoding a large picture is as before.
- 新做法 **修手·先放大再修**:你递给 AI 一张手画坏的图,AMB 先把整张图放大 1.5 倍轻轻重画一遍,让手变大、模型有地方画手指,再自动找出每只手、放大重画后贴回去。这是照着参考作者的做法,在 6GB 的笔记本显卡上一组组试出来的:只修手不先放大,大约一半能成;先放大再修,大约 4 张里 3 张能成。Anima 模型上有 Anima Turbo LoRA(做法面板里可以下载)时只跑 10 步,1280×832 的图约 75 秒;没有也能用,慢三倍左右。AI 会一次出 4 张,先自己放大看手,把手指数不对、粘在一起、大小不对的去掉,都不行就换种子再来,最多两轮,再让你在只放大手那一块的面板里挑。整张图会有些细小变化(脸、水花),构图不变。
- New way **Fix hands: enlarge, then fix**: from a picture with bad hands, Anomalous enlarges the whole picture 1.5× and redraws it lightly, so the hands grow and the model has room for fingers, then finds every hand and redraws it larger. Taken from the reference author's workflows and tried step by step on a 6 GB laptop card: the hand pass alone fixed about half the tries, enlarging first about 3 in 4. On an Anima model with the Anima Turbo LoRA (downloadable in the ways panel) it is 10 steps, about 75 s for 1280×832; without it, about three times slower. The AI makes 4 tries, checks the hands itself first, drops wrong finger counts, fused fingers and wrong sizes, tries new seeds at most twice more, and lets you pick in a panel zoomed on the hand. Small things change over the picture (faces, splashes); the layout stays.
- 新做法 **修手·先放大再修**:你递给 AI 一张手画坏的图,AMB 先把整张图放大到约 400 万像素(原图越小放得越大:1280×832 这种放 2 倍,已经很大的图不放,最多 2 倍)轻轻重画一遍,让手变大、模型有地方画手指,再自动找出每只手、放大重画后贴回去。这是照着参考作者的做法,在 6GB 的笔记本显卡上一组组试出来的:只修手不先放大,大约一半能成;先放大 1.5 倍再修,大约 4 张里 3 张能成;放大 2 倍,同样的种子手指更清楚。Anima 模型上有 Anima Turbo LoRA(做法面板里可以下载)时只跑 10 步,1280×832 的图约 100 秒;没有也能用,慢三倍左右。AI 会一次出 4 张,先自己放大看手,把手指数不对、粘在一起、大小不对的去掉,都不行就换种子再来,最多两轮,再让你在只放大手那一块的面板里挑。整张图会有些细小变化(脸、水花),构图不变。
- New way **Fix hands: enlarge, then fix**: from a picture with bad hands, Anomalous enlarges the whole picture to about 4 megapixels (the smaller it is, the more: 2× for 1280×832, not at all for a large one, at most 2×) and redraws it lightly, so the hands grow and the model has room for fingers, then finds every hand and redraws it larger. Taken from the reference author's workflows and tried step by step on a 6 GB laptop card: the hand pass alone fixed about half the tries, enlarging 1.5× first about 3 in 4, and 2× gave sharper fingers in the same seeds. On an Anima model with the Anima Turbo LoRA (downloadable in the ways panel) it is 10 steps, about 100 s for 1280×832; without it, about three times slower. The AI makes 4 tries, checks the hands itself first, drops wrong finger counts, fused fingers and wrong sizes, tries new seeds at most twice more, and lets you pick in a panel zoomed on the hand. Small things change over the picture (faces, splashes); the layout stays.
- **修一处(比如一只手)更容易成**:从 Codex 这几天修手的试验看,重画的力度太大时,新画的手会撑满你圈的范围,于是手越修越大。现在“局部重绘”默认力度降到修东西用的 0.45(官方节点那块 0.5),AI 也会被告知:圈得贴着手、保持低力度、一次出 4 张,再用一个**只放大手那一块**的挑选面板给你挑,挑完用同样放大的前后对比给你看。展台上的“挑一张”和前后对比滑块都能只显示每张图的同一小块。
- **Fixing one spot (a hand) works more often**: Codex's hand tests showed that with a strong repaint the new hand fills the whole marked area and grows each time. The repaint block's strength is now 0.45 by default, a fix (0.5 for the built-in one), and the AI is told to mark tightly, keep it low, make 4 tries and let you pick in a picks panel **zoomed on the hand**, then show before and after zoomed the same. The stage's picks and slider can show the same small part of every picture.
+14 -9
View File
@@ -3,13 +3,18 @@
"want": "hands",
"rank": 2,
"short": "enlarge, then hands",
"enlarge": {
"megapixels": 4.2,
"most": 2.0,
"unknown": 1.5
},
"title": {
"zh": "修手·先放大再修",
"en": "Fix hands: enlarge, then fix"
},
"about": {
"zh": "整张图放大 1.5 倍轻轻重画,让手变大;再找出每只手,放大重画后贴回去。",
"en": "The whole picture is enlarged 1.5× and redrawn lightly, so the hands grow; then each hand is found, redrawn larger and pasted back."
"zh": "整张图放大到约 400 万像素(小图 2 倍)轻轻重画,让手变大;再找出每只手,放大重画后贴回去。",
"en": "The whole picture is enlarged to about 4 megapixels (2× for a small one) and redrawn lightly, so the hands grow; then each hand is found, redrawn larger and pasted back."
},
"source": {
"zh": "参考作者的「先放大重画」和「手部精修」两步合在一起,2026-10-29 在 RTX 4050 上试出这组数",
@@ -43,7 +48,7 @@
0
],
"upscale_method": "lanczos",
"scale_by": 1.5
"scale_by": "$enlarge"
}
},
"encode": {
@@ -119,8 +124,8 @@
}
}
},
"after": "The picture is enlarged 1.5× and drawn again lightly (the sampler now takes it, at denoise 0.4), then every hand found is redrawn larger (hands, denoise 0.45) and saved with prefix hands_fixed; the enlarged one is saved too, without the hand pass. About 3 tries in 4 give a good hand: run_workflow with batch 4 (each try its own seed), then check them before the user does: zoom_image each hands_fixed picture on the hand, compare_with the old picture, and drop a hand with the wrong number of fingers, fused or melted fingers, or one far bigger or smaller than its arm. None good: run_workflow batch 4 again, at most twice. Then a picks panel zoomed on the hand lets the user choose among the good ones. A picture over about 1.6 megapixels: lower bigger's scale_by so it ends near 2.4 megapixels.",
"notes": "Tried on the Codex test picture (1280×832, three characters, the hand about 110×78 px): the hand pass alone gave a good hand in about half the seeds whatever its size (512 or 768) and denoise (0.45 or 0.55); enlarging 1.5× first gave good hands in 3 of 4. Denoise 0.4 for the enlarged redraw kept the layout; faces and splashes change a little.",
"after": "The picture is enlarged to about 4 megapixels (2× for one of about 1 megapixel, at most 2×, not at all for a large one) and drawn again lightly (the sampler now takes it, at denoise 0.4), then every hand found is redrawn larger (hands, denoise 0.45) and saved with prefix hands_fixed; the enlarged one is saved too, without the hand pass. About 3 tries in 4 give a good hand: run_workflow with batch 4 (each try its own seed), then check them before the user does: zoom_image each hands_fixed picture on the hand, compare_with the old picture, and drop a hand with the wrong number of fingers, fused or melted fingers, or one far bigger or smaller than its arm. None good: run_workflow batch 4 again, at most twice. Then a picks panel zoomed on the hand lets the user choose among the good ones.",
"notes": "Tried on the Codex test picture (1280×832, three characters, the hand about 110×78 px): the hand pass alone gave a good hand in about half the seeds whatever its size (512 or 768) and denoise (0.45 or 0.55); enlarging 1.5× first gave good hands in 3 of 4, 2× gave sharper fingers in the same seeds (about 105 s instead of 75 s). Denoise 0.4 for the enlarged redraw kept the layout; faces and splashes change a little.",
"models": [
"hand_yolov8s",
"anima_turbo_lora"
@@ -132,8 +137,8 @@
"runs": [
{
"model": "Anima (Kirazuri v4, Turbo LoRA)",
"size": "1280×832 → 1920×1248",
"seconds": 75
"size": "1280×832 → 2560×1664",
"seconds": 105
}
]
},
@@ -179,7 +184,7 @@
0
],
"upscale_method": "lanczos",
"scale_by": 1.5
"scale_by": "$enlarge"
}
},
"encode": {
@@ -259,7 +264,7 @@
}
}
},
"after": "On this Anima model the Anima Turbo LoRA (0.7) makes both passes 10 steps at CFG 1, about 75 s for 1280×832 on a 6 GB card. The picture is enlarged 1.5× and drawn again lightly (the sampler now takes it, at denoise 0.4), then every hand found is redrawn larger (hands, denoise 0.45) and saved with prefix hands_fixed; the enlarged one is saved too, without the hand pass. About 3 tries in 4 give a good hand: run_workflow with batch 4 (each try its own seed), then check them before the user does: zoom_image each hands_fixed picture on the hand, compare_with the old picture, and drop a hand with the wrong number of fingers, fused or melted fingers, or one far bigger or smaller than its arm. None good: run_workflow batch 4 again, at most twice. Then a picks panel zoomed on the hand lets the user choose among the good ones. A picture over about 1.6 megapixels: lower bigger's scale_by so it ends near 2.4 megapixels."
"after": "On this Anima model the Anima Turbo LoRA (0.7) makes both passes 10 steps at CFG 1, about 105 s for 1280×832 (2×) on a 6 GB card. The picture is enlarged to about 4 megapixels (2× for one of about 1 megapixel, at most 2×, not at all for a large one) and drawn again lightly (the sampler now takes it, at denoise 0.4), then every hand found is redrawn larger (hands, denoise 0.45) and saved with prefix hands_fixed; the enlarged one is saved too, without the hand pass. About 3 tries in 4 give a good hand: run_workflow with batch 4 (each try its own seed), then check them before the user does: zoom_image each hands_fixed picture on the hand, compare_with the old picture, and drop a hand with the wrong number of fingers, fused or melted fingers, or one far bigger or smaller than its arm. None good: run_workflow batch 4 again, at most twice. Then a picks panel zoomed on the hand lets the user choose among the good ones."
}
}
}
+3 -1
View File
@@ -12,6 +12,7 @@ import time
from . import ai_pictures, ai_tasks, ai_toolbox, mcp_fill, model_advice, model_download, reference_blocks
from .mcp_actions import _action, _local, _page
from .media_routes import picture_size
from .mcp_tools import ToolError
MAX_FOUND = 20
@@ -239,7 +240,8 @@ def add_nodes(ctx, nodes=None, near_node_id=None, replace=False, block=None, ima
if reference_blocks.BLOCKS.get(str(block), {}).get("scene") and scene:
scene = ai_pictures.to_input(scene)
def build(): # a ready-made block (reference_blocks.py): its roles are found on the canvas, what it cannot splice it replaces
return reference_blocks.build(str(block), object_info(ctx), image, lambda: _main_base(near_node_id), _base_of, scene)
return reference_blocks.build(str(block), object_info(ctx), image, lambda: _main_base(near_node_id), _base_of, scene,
lambda name: picture_size(ai_tasks.folder_paths.get_annotated_filepath(name)))
try:
try:
built = build()
+14 -2
View File
@@ -17,6 +17,7 @@ and the user has not turned off (user/anomalous/ai_blocks.json), a few words eac
"""
import json
import math
import os
import re
import threading
@@ -313,10 +314,19 @@ def nodes_of(name, info, image=None, main_base=lambda: "", base_of=lambda name:
return build(name, info, image, main_base, base_of)["nodes"]
def build(name, info, image=None, main_base=lambda: "", base_of=lambda name: "", scene=None):
def enlargement(rule, size):
"""How many times a block enlarges a picture of `size` (width, height; None: unknown) so it ends
near rule["megapixels"]: never smaller, at most rule["most"], rule["unknown"] without a size."""
if not size:
return rule["unknown"]
return round(min(rule["most"], max(1.0, math.sqrt(rule["megapixels"] * 1_000_000 / (size[0] * size[1])))), 2)
def build(name, info, image=None, main_base=lambda: "", base_of=lambda name: "", scene=None, size_of=lambda image: None):
"""Block `name` built for this canvas: {nodes (add_nodes' group, its values filled in), roles, after},
or BlockError saying why not. A block with variants or a ControlNet asks `main_base()` (once) for
the canvas's model's base model, and `base_of` for each ControlNet's."""
the canvas's model's base model, and `base_of` for each ControlNet's; one that enlarges the picture
by its size ("enlarge") asks `size_of(image)`."""
block = BLOCKS.get(name)
if not block:
raise BlockError(f"No block {name!r}; there are: {', '.join(BLOCKS)}.")
@@ -345,6 +355,8 @@ def build(name, info, image=None, main_base=lambda: "", base_of=lambda name: "",
fills[f"${role}"] = _detector(info, prefix)
for role, prefix in (block.get("loras") or {}).items():
fills[f"${role}"] = _lora(info, prefix)
if block.get("enlarge"):
fills["$enlarge"] = enlargement(block["enlarge"], size_of(fills["$image"]))
if block.get("upscaler"):
fills["$upscaler"], times = _upscaler(info, block.get("upscale_by", 2.0))
fills["$fit"] = round(block.get("upscale_by", 1) / times, 4) # the model's 4× brought back to the block's size
+1 -1
View File
@@ -148,7 +148,7 @@ claude mcp add --transport http anomalous http://127.0.0.1:8188/anomalous/mcp
**让 AI 局部重绘**:标注里选 **▧ 涂重绘区**,用笔刷把要重画的地方涂上(笔刷粗细可调;框、圈、画笔圈出的地方也算),右边 **怎么改** 选 **只改标出的地方**(用笔刷时会自动选上)再发给 AI。另外两种是 **交给 AI 判断**(AI 看说明自己定)和 **整张重新出图**(不做局部重绘);你选的会作为你的要求写在 AI 收到的第一句,时间线里那条标注也写着“改法:…”。AMB 会在 ComfyUI 的 input 文件夹里放一张 `anomalous_inpaint_….png`:原图加上你涂的区域做遮罩。AI 收到时会被告诉怎么用它(LoadImage 读进来就带遮罩,用原图的模型和提示词,重绘强度 0.5~0.8 保留原样子,1.0 完全重画),不确定时用选择题问你强度,画完用前后对比给你看。这张文件删任务时不会删,因为你的工作流可能还在用它。
**参考做法**:有几件常见的活,AMB 带着现成的做法,是从擅长这些活的工作流里提炼出来的:**局部重绘·裁切缝合**(圈出的地方裁出来放大到 1024 重画再缝回去,需要节点包 ComfyUI-Inpaint-CropAndStitch)、**局部重绘(官方节点)**(没装那个包时用)、**局部重绘·LanPaint**(融合最好、任何模型都行,但慢好几倍,需要节点包 LanPaint)、**放大**(1.25 倍再轻轻重画一遍,只用自带节点,另存一张,文件名以 upscaled 开头)、**分块放大**(2 倍,需要节点包 ComfyUI_UltimateSDUpscale)、**照着姿势画**和**照着构图画**(你递给 AI 一张图,AMB 读出姿势或深度,挑一个和底模对得上的控制网,需要节点包 comfyui_controlnet_aux)、**迭代放大**(分 3 小步放大到 1.3 倍,用 Impact Pack)、**双模型放大**(重画换一个更稳的模型)、**背景移除**(需要节点包 comfyui-inspyrenet-rembg)、**读图出标签**(需要节点包 ComfyUI-WD14-Tagger,AI 跑完会收到读出的标签)、**部位细化(脸和手)**(需要 Impact Pack、Impact Subpack 和 models/ultralytics/bbox 里的检测模型,细化后的图另存一张,文件名以 detailed 开头)、**修手·先放大再修**(你递给 AI 一张图:整张放大 1.5 倍轻轻重画,让手变大,再逐只修手,另存一张,文件名以 hands_fixed 开头;Anima 模型上有 Anima Turbo LoRA 时只跑 10 步,6GB 显卡约 75 秒。AI 一次出 4 张,自己先放大看手,把手指数不对、粘连、大小不对的去掉,都不行就再出 4 张,最多两轮,再把好的放进只放大手那块的面板让你挑)。AI 工作台右边的**做法**面板列着全部做法:缺节点包或模型的变灰并写明缺什么,每块有个开关,关掉的 AI 就看不到。AI 开工时只收到开着又能用的那些;它说用哪块,AMB 就把那几个节点搭好、接进画布上那个出图的工作流里(采样器、VAE 解码、保存图片都由 AMB 按插口认出来),一次就好,也是一步 Ctrl+Z。画布上有好几个采样器时,AI 得指明用哪一个;缺节点包时,它会知道缺哪个、该用哪块代替。
**参考做法**:有几件常见的活,AMB 带着现成的做法,是从擅长这些活的工作流里提炼出来的:**局部重绘·裁切缝合**(圈出的地方裁出来放大到 1024 重画再缝回去,需要节点包 ComfyUI-Inpaint-CropAndStitch)、**局部重绘(官方节点)**(没装那个包时用)、**局部重绘·LanPaint**(融合最好、任何模型都行,但慢好几倍,需要节点包 LanPaint)、**放大**(1.25 倍再轻轻重画一遍,只用自带节点,另存一张,文件名以 upscaled 开头)、**分块放大**(2 倍,需要节点包 ComfyUI_UltimateSDUpscale)、**照着姿势画**和**照着构图画**(你递给 AI 一张图,AMB 读出姿势或深度,挑一个和底模对得上的控制网,需要节点包 comfyui_controlnet_aux)、**迭代放大**(分 3 小步放大到 1.3 倍,用 Impact Pack)、**双模型放大**(重画换一个更稳的模型)、**背景移除**(需要节点包 comfyui-inspyrenet-rembg)、**读图出标签**(需要节点包 ComfyUI-WD14-Tagger,AI 跑完会收到读出的标签)、**部位细化(脸和手)**(需要 Impact Pack、Impact Subpack 和 models/ultralytics/bbox 里的检测模型,细化后的图另存一张,文件名以 detailed 开头)、**修手·先放大再修**(你递给 AI 一张图:整张放大到约 400 万像素轻轻重画,原图越小放得越大,最多 2 倍,让手变大,再逐只修手,另存一张,文件名以 hands_fixed 开头;Anima 模型上有 Anima Turbo LoRA 时只跑 10 步,1280×832 的图在 6GB 显卡上约 100 秒。AI 一次出 4 张,自己先放大看手,把手指数不对、粘连、大小不对的去掉,都不行就再出 4 张,最多两轮,再把好的放进只放大手那块的面板让你挑)。AI 工作台右边的**做法**面板列着全部做法:缺节点包或模型的变灰并写明缺什么,每块有个开关,关掉的 AI 就看不到。AI 开工时只收到开着又能用的那些;它说用哪块,AMB 就把那几个节点搭好、接进画布上那个出图的工作流里(采样器、VAE 解码、保存图片都由 AMB 按插口认出来),一次就好,也是一步 Ctrl+Z。画布上有好几个采样器时,AI 得指明用哪一个;缺节点包时,它会知道缺哪个、该用哪块代替。
**先对一下重画的范围**:圈得不准也没关系。AI 准备只重画标出的地方时,会先在展台把 **你圈的** 和 **AI 调整后** 的范围并排给你看(红色是要重画的地方;AI 可以挪位置、改成方框或椭圆、往外扩、把边缘做软,图下写着外扩和羽化了多少像素)。点 **用 AI 调整的**、**用我圈的** 或 **我重新圈**,也可以在下面写一句(比如“再往手腕多圈一点”),AI 会照着再调一次;点 **让 AI 定** 就用 AI 调整的。选好以后 AMB 才把带这个范围的 `anomalous_inpaint_….png` 放进 input 文件夹,节点怎么搭由 AI 自己来。
+4
View File
@@ -127,6 +127,10 @@ class BlockTests(unittest.TestCase):
self.assertEqual((nodes["picture"]["inputs"]["image"], nodes["bigger"]["inputs"]["scale_by"], nodes["encode"]["wire_to"]),
("elves.png", 1.5, "$sampler"), "the picture, enlarged, in the sampler's place of its latent")
self.assertEqual(built["roles"], {"sampler": {"denoise": 0.4}})
# The smaller the picture, the more it is enlarged: to about 4 megapixels, 1× to 2×.
sized = lambda size: reference_blocks.build("fix_hands", EVERYTHING, "elves.png", lambda: "", size_of=lambda name: size)["nodes"]["bigger"]["inputs"]["scale_by"] # noqa: E731
self.assertEqual([sized((1280, 832)), sized((832, 1216)), sized((1536, 1024)), sized((2048, 2048)), sized((640, 480))],
[1.99, 2.0, 1.63, 1.0, 2.0])
self.assertEqual((nodes["hand_finder"]["inputs"]["model_name"], nodes["hands"]["inputs"]["denoise"], nodes["hands"]["inputs"]["guide_size"]),
("bbox/hand_yolov8s.pt", 0.45, 768))
self.assertNotIn("turbo", nodes)