class MaskComposite:
# 定义一个名为 MaskComposite 的类
@classmethod
def INPUT_TYPES(cls):
# 定义一个类方法 INPUT_TYPES
return {
"required": {
"destination": ("MASK",),
# 需要输入的目标掩码
"source": ("MASK",),
# 需要输入的源掩码
"x": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 1}),
# 组合操作的 x 坐标,默认值为 0,范围从 0 到 MAX_RESOLUTION
"y": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 1}),
# 组合操作的 y 坐标,默认值为 0,范围从 0 到 MAX_RESOLUTION
"operation": (["multiply", "add", "subtract", "and", "or", "xor"],),
# 组合操作类型,包括 "multiply"、"add"、"subtract"、"and"、"or" 和 "xor"
}
}
CATEGORY = "mask"
# 指定类别为 "mask"
RETURN_TYPES = ("MASK",)
# 指定返回类型为 "MASK"
FUNCTION = "combine"
# 指定主要功能函数为 "combine"
def combine(self, destination, source, x, y, operation):
# 定义一个实例方法 combine
output = destination.reshape((-1, destination.shape[-2], destination.shape[-1])).clone()
# 重塑目标掩码并克隆为输出掩码
source = source.reshape((-1, source.shape[-2], source.shape[-1]))
# 重塑源掩码
left, top = (x, y,)
# 设置左上角坐标
right, bottom = (min(left + source.shape[-1], destination.shape[-1]), min(top + source.shape[-2], destination.shape[-2]))
# 设置右下角坐标,确保不超过目标掩码的边界
visible_width, visible_height = (right - left, bottom - top,)
# 计算可见区域的宽度和高度
source_portion = source[:, :visible_height, :visible_width]
# 获取源掩码中可见区域的部分
destination_portion = destination[:, top:bottom, left:right]
# 获取目标掩码中相应区域的部分
if operation == "multiply":
output[:, top:bottom, left:right] = destination_portion * source_portion
# 乘法操作,将源和目标部分相乘
elif operation == "add":
output[:, top:bottom, left:right] = destination_portion + source_portion
# 加法操作,将源和目标部分相加
elif operation == "subtract":
output[:, top:bottom, left:right] = destination_portion - source_portion
# 减法操作,将源部分从目标部分减去
elif operation == "and":
output[:, top:bottom, left:right] = torch.bitwise_and(destination_portion.round().bool(), source_portion.round().bool()).float()
# 按位与操作,将源和目标部分进行按位与
elif operation == "or":
output[:, top:bottom, left:right] = torch.bitwise_or(destination_portion.round().bool(), source_portion.round().bool()).float()
# 按位或操作,将源和目标部分进行按位或
elif operation == "xor":
output[:, top:bottom, left:right] = torch.bitwise_xor(destination_portion.round().bool(), source_portion.round().bool()).float()
# 按位异或操作,将源和目标部分进行按位异或
output = torch.clamp(output, 0.0, 1.0)
# 将输出掩码的值限制在 0.0 到 1.0 之间
return (output,)
# 返回输出掩码元组
主要步骤和功能
-
定义输入类型:
INPUT_TYPES
类方法指定了这个类所需的输入类型,包括目标掩码 (destination
)、源掩码 (source
)、组合操作的坐标 (x
和y
),以及组合操作类型 (operation
)。
-
类别和返回类型:
CATEGORY
指定了类别为mask
。RETURN_TYPES
指定了返回类型为MASK
。FUNCTION
指定了主要功能函数为combine
。
-
组合方法:
combine
方法是这个类的核心功能。它接受目标掩码、源掩码、组合操作的坐标和操作类型作为输入。- 首先,重塑目标掩码和源掩码,并设置组合操作的坐标。
- 根据操作类型,执行相应的组合操作(乘法、加法、减法、按位与、按位或、按位异或)。
- 最后,将结果限制在 0.0 到 1.0 之间,并返回结果掩码。
总的来说,MaskComposite
类的作用是通过不同的操作类型,将源掩码与目标掩码进行组合,生成新的掩码。这个类可以集成到如图像处理或掩码操作的系统中,提供灵活的掩码合成功能。
class MaskBlur:
# 定义一个名为 MaskBlur 的类
@classmethod
def INPUT_TYPES(s):
# 定义一个类方法 INPUT_TYPES,返回输入参数的类型
return {
"required": {
"mask": ("MASK",),
# 输入的掩码图像
"amount": ("INT", { "default": 6, "min": 0, "max": 256, "step": 1, }),
# 模糊量,默认值为 6,最小值为 0,最大值为 256,步长为 1
"device": (["auto", "cpu", "gpu"],),
# 计算设备选项,可以是 "auto"、"cpu" 或 "gpu"
}
}
RETURN_TYPES = ("MASK",)
# 返回类型为掩码
FUNCTION = "execute"
# 定义主要功能函数为 "execute"
CATEGORY = "essentials/mask"
# 设置类别为 "essentials/mask"
def execute(self, mask, amount, device):
# 定义掩码模糊处理的主要功能
if amount == 0:
return (mask,)
# 如果模糊量为 0,直接返回原始掩码
if "gpu" == device:
mask = mask.to(comfy.model_management.get_torch_device())
# 如果设备为 "gpu",将掩码转移到 GPU 上
elif "cpu" == device:
mask = mask.to('cpu')
# 如果设备为 "cpu",将掩码转移到 CPU 上
if amount % 2 == 0:
amount += 1
# 如果模糊量为偶数,将其加 1,使其成为奇数
if mask.dim() == 2:
mask = mask.unsqueeze(0)
# 如果掩码的维度为 2,增加一个维度使其成为 3 维
mask = T.functional.gaussian_blur(mask.unsqueeze(1), amount).squeeze(1)
# 对掩码应用高斯模糊,首先增加一个通道维度,然后在模糊后移除该维度
if "gpu" == device or "cpu" == device:
mask = mask.to(comfy.model_management.intermediate_device())
# 如果设备为 "gpu" 或 "cpu",将掩码转移回中间设备
return (mask,)
# 返回模糊处理后的掩码
-
定义输入类型:
INPUT_TYPES
类方法指定了这个类所需的输入类型,包括掩码图像 (mask
)、模糊量 (amount
)、计算设备 (device
)。
-
定义返回类型:
RETURN_TYPES
指定了返回类型为MASK
。FUNCTION
定义主要功能函数为execute
。CATEGORY
设置类别为essentials/mask
。
-
掩码模糊方法:
execute
方法是这个类的核心功能。它接受掩码图像、模糊量和计算设备作为输入。- 如果模糊量为 0,直接返回原始掩码。
- 根据设备选项,将掩码图像转移到相应的设备(GPU 或 CPU)。
- 如果模糊量为偶数,将其加 1,使其成为奇数以适应高斯模糊操作。
- 如果掩码的维度为 2,增加一个维度使其成为 3 维,以适应高斯模糊操作。
- 使用
T.functional.gaussian_blur
函数对掩码图像进行高斯模糊处理。 - 根据设备选项,将模糊处理后的掩码图像转移回中间设备(如果适用)。
- 返回模糊处理后的掩码。
这个类的主要作用是对输入的掩码图像应用高斯模糊处理,适用于需要平滑或模糊处理掩码图像的场景。
class imageDetailTransfer:
# 定义一个名为 imageDetailTransfer 的类
@classmethod
def INPUT_TYPES(s):
# 定义一个类方法 INPUT_TYPES,返回输入参数的类型
return {
"required": {
"target": ("IMAGE",),
# 目标图像
"source": ("IMAGE",),
# 源图像
"mode": (["add", "multiply", "screen", "overlay", "soft_light", "hard_light", "color_dodge", "color_burn", "difference", "exclusion", "divide",],{"default": "add"}),
# 图像混合模式,默认值为 "add"
"blur_sigma": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 100.0, "step": 0.01}),
# 高斯模糊的标准差,默认值为 1.0
"blend_factor": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.001, "round": 0.001}),
# 混合因子,默认值为 1.0
"image_output": (["Hide", "Preview", "Save", "Hide/Save"], {"default": "Preview"}),
# 图像输出选项,默认值为 "Preview"
"save_prefix": ("STRING", {"default": "ComfyUI"}),
# 保存文件的前缀,默认值为 "ComfyUI"
},
"optional": {
"mask": ("MASK",),
# 可选掩码图像
},
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
# 隐藏的参数,包括提示和额外的 PNG 信息
}
RETURN_TYPES = ("IMAGE",)
# 返回类型为图像
RETURN_NAMES = ("image",)
# 返回的名称为图像
OUTPUT_NODE = True
# 设定为输出节点
FUNCTION = "transfer"
# 定义主要功能函数为 "transfer"
CATEGORY = "EasyUse/Image"
# 设置类别为 "EasyUse/Image"
def transfer(self, target, source, mode, blur_sigma, blend_factor, image_output, save_prefix, mask=None, prompt=None, extra_pnginfo=None):
# 定义图像细节转移的主要功能
batch_size, height, width, _ = target.shape
# 获取目标图像的批量大小、高度和宽度
device = comfy.model_management.get_torch_device()
# 获取计算设备(CPU 或 GPU)
target_tensor = target.permute(0, 3, 1, 2).clone().to(device)
# 调整目标图像张量的维度顺序,并复制到计算设备
source_tensor = source.permute(0, 3, 1, 2).clone().to(device)
# 调整源图像张量的维度顺序,并复制到计算设备
if target.shape[1:] != source.shape[1:]:
source_tensor = comfy.utils.common_upscale(source_tensor, width, height, "bilinear", "disabled")
# 如果源图像和目标图像的尺寸不同,使用双线性插值将源图像调整到目标图像的大小
if source.shape[0] < batch_size:
source = source[0].unsqueeze(0).repeat(batch_size, 1, 1, 1)
# 如果源图像的批量大小小于目标图像,重复源图像使其批量大小匹配
kernel_size = int(6 * int(blur_sigma) + 1)
# 计算高斯模糊的核大小
gaussian_blur = GaussianBlur(kernel_size=(kernel_size, kernel_size), sigma=(blur_sigma, blur_sigma))
# 创建高斯模糊操作
blurred_target = gaussian_blur(target_tensor)
# 对目标图像进行高斯模糊
blurred_source = gaussian_blur(source_tensor)
# 对源图像进行高斯模糊
if mode == "add":
new_image = (source_tensor - blurred_source) + blurred_target
# 如果模式为 "add",执行加法混合
elif mode == "multiply":
new_image = source_tensor * blurred_target
# 如果模式为 "multiply",执行乘法混合
elif mode == "screen":
new_image = 1 - (1 - source_tensor) * (1 - blurred_target)
# 如果模式为 "screen",执行屏幕混合
elif mode == "overlay":
new_image = torch.where(blurred_target < 0.5, 2 * source_tensor * blurred_target,
1 - 2 * (1 - source_tensor) * (1 - blurred_target))
# 如果模式为 "overlay",执行叠加混合
elif mode == "soft_light":
new_image = (1 - 2 * blurred_target) * source_tensor ** 2 + 2 * blurred_target * source_tensor
# 如果模式为 "soft_light",执行柔光混合
elif mode == "hard_light":
new_image = torch.where(source_tensor < 0.5, 2 * source_tensor * blurred_target,
1 - 2 * (1 - source_tensor) * (1 - blurred_target))
# 如果模式为 "hard_light",执行强光混合
elif mode == "difference":
new_image = torch.abs(blurred_target - source_tensor)
# 如果模式为 "difference",执行差值混合
elif mode == "exclusion":
new_image = 0.5 - 2 * (blurred_target - 0.5) * (source_tensor - 0.5)
# 如果模式为 "exclusion",执行排除混合
elif mode == "color_dodge":
new_image = blurred_target / (1 - source_tensor)
# 如果模式为 "color_dodge",执行颜色减淡混合
elif mode == "color_burn":
new_image = 1 - (1 - blurred_target) / source_tensor
# 如果模式为 "color_burn",执行颜色加深混合
elif mode == "divide":
new_image = (source_tensor / blurred_source) * blurred_target
# 如果模式为 "divide",执行除法混合
else:
new_image = source_tensor
# 其他情况,直接使用源图像
new_image = torch.lerp(target_tensor, new_image, blend_factor)
# 根据混合因子在目标图像和新图像之间进行线性插值
if mask is not None:
mask = mask.to(device)
new_image = torch.lerp(target_tensor, new_image, mask)
# 如果提供了掩码,根据掩码在目标图像和新图像之间进行线性插值
new_image = torch.clamp(new_image, 0, 1)
# 将新图像的值限制在 0 到 1 之间
new_image = new_image.permute(0, 2, 3, 1).cpu().float()
# 调整新图像的维度顺序,并将其转换回 CPU 和浮点格式
results = easySave(new_image, save_prefix, image_output, prompt, extra_pnginfo)
# 调用 easySave 函数保存新图像,并获取结果
if image_output in ("Hide", "Hide/Save"):
return {"ui": {},
"result": (new_image,)}
# 如果图像输出设置为 "Hide" 或 "Hide/Save",返回隐藏的结果
return {"ui": {"images": results},
"result": (new_image,)}
# 返回 UI 和结果图像
主要步骤和功能
-
定义输入类型:
INPUT_TYPES
类方法指定了这个类所需的输入类型,包括目标图像 (target
)、源图像 (source
)、混合模式 (mode
)、高斯模糊标准差 (blur_sigma
)、混合因子 (blend_factor
)、图像输出选项 (image_output
)、保存前缀 (save_prefix
)、以及可选的掩码 (mask
)。
-
定义返回类型:
RETURN_TYPES
指定了返回类型为IMAGE
。RETURN_NAMES
指定了返回名称为image
。OUTPUT_NODE
指定为输出节点。FUNCTION
定义主要功能函数为transfer
。CATEGORY
设置类别为EasyUse/Image
。
-
图像细节转移方法:
transfer
方法是这个类的核心功能。它接受目标图像、源图像、混合模式、模糊强度、混合因子、图像输出选项、保存前缀以及可选的掩码作为输入。- 对目标图像和源图像进行处理,包括调整尺寸、批量大小、高斯模糊等。
- 根据不同的混合模式,对源图像和目标图像进行相应的混合操作。
- 使用混合因子在目标图像和新图像之间进行线性插值,如果提供了掩码,则根据掩码进行插值。
- 将新图像的值限制在 0 到 1 之间,并调整维度顺序。
- 调用
easySave
函数保存新图像,并根据输出选项返回结果。
这个类的主要作用是通过各种图像混合模式和参数设置,实现图像的细节转移和混合处理,适用于图像增强和细节处理的任务。