Skip to content

Commit e979c44

Browse files
更像传参方式
1 parent b77b199 commit e979c44

File tree

3 files changed

+320
-129
lines changed

3 files changed

+320
-129
lines changed

nodes.py

Lines changed: 78 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,97 +10,136 @@
1010
import numpy as np
1111
import logging
1212

13+
1314
class PhotoDoodleSamplerAdvanced(SamplerCustomAdvanced):
1415
"""
1516
扩展的自定义采样器,支持额外的条件图像和位置编码选项
1617
自动处理掩码和引导强度
1718
"""
18-
19+
1920
@classmethod
2021
def INPUT_TYPES(s):
2122
# 继承原始输入类型并添加新的参数
2223
original_inputs = SamplerCustomAdvanced.INPUT_TYPES()
23-
24+
2425
# 添加新的必需参数,但移除不需要的参数
25-
original_inputs["required"].update({
26-
"condition_image": ("LATENT", {"default": None}),
27-
"use_clone_pe": ("BOOLEAN", {"default": False}),
28-
})
29-
26+
original_inputs["required"].update(
27+
{
28+
"condition_image": ("LATENT", {"default": None}),
29+
"use_clone_pe": ("BOOLEAN", {"default": False}),
30+
}
31+
)
32+
3033
# 不需要可选参数,使用内部默认值
3134
# original_inputs["optional"] = {}
32-
35+
3336
return original_inputs
3437

3538
RETURN_TYPES = SamplerCustomAdvanced.RETURN_TYPES
3639
RETURN_NAMES = SamplerCustomAdvanced.RETURN_NAMES
3740
FUNCTION = "sample_with_condition"
3841
CATEGORY = "sampling/custom_sampling"
3942

40-
def sample_with_condition(self, noise, guider, sampler, sigmas, latent_image,
41-
condition_image=None, use_clone_pe=False):
43+
def sample_with_condition(
44+
self,
45+
noise,
46+
guider,
47+
sampler,
48+
sigmas,
49+
latent_image,
50+
condition_image=None,
51+
use_clone_pe=False,
52+
):
4253
"""
4354
扩展的采样函数,支持条件图像和自定义位置编码
4455
自动处理掩码和引导强度
4556
"""
4657
latent = latent_image
4758
latent_image = latent["samples"]
4859
latent = latent.copy()
49-
latent_image = comfy.sample.fix_empty_latent_channels(guider.model_patcher, latent_image)
60+
latent_image = comfy.sample.fix_empty_latent_channels(
61+
guider.model_patcher, latent_image
62+
)
5063
latent["samples"] = latent_image
5164

5265
# 处理条件图像
5366
cond_latent = None
5467
if condition_image is not None:
5568
cond_latent = condition_image["samples"]
56-
69+
5770
# 确保条件图像在与潜在图像相同的设备上
5871
# 一次性移动到 GPU,避免每次推理都移动
5972
target_device = comfy.model_management.get_torch_device()
6073
if cond_latent.device != target_device:
61-
logging.info(f"将条件图像从 {cond_latent.device} 移动到 {target_device}")
74+
logging.info(
75+
f"将条件图像从 {cond_latent.device} 移动到 {target_device}"
76+
)
6277
cond_latent = cond_latent.to(target_device)
63-
78+
79+
# 记录条件图像的形状和设备
80+
logging.debug(
81+
f"条件图像: shape={cond_latent.shape}, device={cond_latent.device}"
82+
)
83+
6484
# 创建去噪掩码 - 只对非条件部分应用去噪
6585
noise_mask = None
6686
if "noise_mask" in latent:
6787
noise_mask = latent["noise_mask"]
68-
88+
logging.debug(f"使用噪声掩码: shape={noise_mask.shape}")
89+
6990
# 准备回调
7091
x0_output = {}
71-
callback = latent_preview.prepare_callback(guider.model_patcher, sigmas.shape[-1] - 1, x0_output)
92+
callback = latent_preview.prepare_callback(
93+
guider.model_patcher, sigmas.shape[-1] - 1, x0_output
94+
)
7295

73-
# 准备额外的关键字参数
96+
# 确保 guider 有 model_options 属性
97+
if not hasattr(guider, "model_options"):
98+
guider.model_options = {}
99+
logging.info("为 guider 创建 model_options 属性")
100+
101+
# 直接设置 model_options
102+
guider.model_options["condition_image"] = cond_latent
103+
guider.model_options["use_clone_pe"] = use_clone_pe
104+
guider.model_options["guider_id"] = id(guider)
105+
106+
# 记录设置的选项
107+
logging.debug(
108+
f"设置 guider.model_options: condition_image={cond_latent is not None}, use_clone_pe={use_clone_pe}"
109+
)
110+
111+
# 准备额外的关键字参数 - 同时通过 kwargs 和 model_options 传递
74112
extra_kwargs = {
75113
"condition_image": cond_latent,
76114
"use_clone_pe": use_clone_pe,
77115
}
78-
116+
79117
# 生成噪声张量
80118
noise_tensor = noise.generate_noise(latent)
81-
119+
82120
# 调用采样器
83121
samples = guider.sample(
84122
noise_tensor,
85-
latent_image,
86-
sampler,
87-
sigmas,
88-
denoise_mask=noise_mask,
89-
callback=callback,
90-
disable_pbar=not comfy.utils.PROGRESS_BAR_ENABLED,
123+
latent_image,
124+
sampler,
125+
sigmas,
126+
denoise_mask=noise_mask,
127+
callback=callback,
128+
disable_pbar=not comfy.utils.PROGRESS_BAR_ENABLED,
91129
seed=noise.seed,
92-
**extra_kwargs
130+
**extra_kwargs,
93131
)
94-
132+
95133
latent["samples"] = samples
96134
return (latent, x0_output.get("x0", None))
97135

136+
98137
class PhotoDoodleCrop:
99138
"""
100139
图片裁切节点:在保持原图比例的情况下,尽可能最大化地裁切出目标宽高的区域
101140
如果原图尺寸不足,则放大至目标尺寸,保持比例且不留白
102141
"""
103-
142+
104143
@classmethod
105144
def INPUT_TYPES(s):
106145
return {
@@ -118,45 +157,45 @@ def INPUT_TYPES(s):
118157
def crop_image(self, image, width, height):
119158
"""
120159
裁切图片,保持比例,最大化填充目标区域,无留白
121-
160+
122161
参数:
123162
image: 输入图片张量 [B, H, W, C]
124163
width: 目标宽度
125164
height: 目标高度
126-
165+
127166
返回:
128167
裁切后的图片张量 [B, height, width, C]
129168
"""
130169
# 转换为numpy处理
131170
result = []
132171
for img in image:
133172
img_np = img.cpu().numpy()
134-
173+
135174
# 获取原始尺寸
136175
orig_h, orig_w = img_np.shape[0], img_np.shape[1]
137-
176+
138177
# 计算目标比例和原始比例
139178
target_ratio = width / height
140179
orig_ratio = orig_w / orig_h
141-
180+
142181
# 策略:先调整比例(缩小或裁切),再缩放到目标尺寸
143182
if orig_ratio > target_ratio:
144183
# 原图更宽,需要调整宽度
145184
new_w = int(orig_h * target_ratio)
146185
offset_w = (orig_w - new_w) // 2
147-
adjusted = img_np[:, offset_w:offset_w+new_w, :]
186+
adjusted = img_np[:, offset_w : offset_w + new_w, :]
148187
else:
149188
# 原图更高,需要调整高度
150189
new_h = int(orig_w / target_ratio)
151190
offset_h = (orig_h - new_h) // 2
152-
adjusted = img_np[offset_h:offset_h+new_h, :]
153-
191+
adjusted = img_np[offset_h : offset_h + new_h, :]
192+
154193
# 调整后的图像缩放到目标尺寸
155194
pil_img = Image.fromarray((adjusted * 255).astype(np.uint8))
156195
resized_pil = pil_img.resize((width, height), Image.LANCZOS)
157196
resized_np = np.array(resized_pil).astype(np.float32) / 255.0
158-
197+
159198
result.append(torch.from_numpy(resized_np))
160-
199+
161200
# 堆叠所有处理后的图片
162-
return (torch.stack(result),)
201+
return (torch.stack(result),)

0 commit comments

Comments
 (0)