from .imagefunc import *
# 从当前目录中的 imagefunc 模块导入所有函数和变量
NODE_NAME = 'ImageBlend'
# 定义节点名称为 'ImageBlend'
class ImageBlend:
# 定义一个名为 ImageBlend 的类
def __init__(self):
# 初始化函数
pass
@classmethod
def INPUT_TYPES(self):
# 定义一个类方法 INPUT_TYPES,返回输入参数的类型
return {
"required": {
"background_image": ("IMAGE", ), # 背景图像
"layer_image": ("IMAGE",), # 图层图像
"invert_mask": ("BOOLEAN", {"default": True}), # 反转掩码,默认值为 True
"blend_mode": (chop_mode,), # 混合模式
"opacity": ("INT", {"default": 100, "min": 0, "max": 100, "step": 1}), # 透明度,默认值为 100,范围从 0 到 100,步长为 1
},
"optional": {
"layer_mask": ("MASK",), # 可选的图层掩码
}
}
RETURN_TYPES = ("IMAGE",)
# 返回类型为图像
RETURN_NAMES = ("image",)
# 返回的名称为图像
FUNCTION = 'image_blend'
# 定义主要功能函数为 'image_blend'
CATEGORY = '😺dzNodes/LayerUtility'
# 设置类别为 '😺dzNodes/LayerUtility'
def image_blend(self, background_image, layer_image, invert_mask, blend_mode, opacity, layer_mask=None):
# 定义图像混合的主要功能
b_images = []
# 初始化背景图像列表
l_images = []
# 初始化图层图像列表
l_masks = []
# 初始化图层掩码列表
ret_images = []
# 初始化返回图像列表
for b in background_image:
b_images.append(torch.unsqueeze(b, 0))
# 将每个背景图像添加到背景图像列表中,并在第 0 维增加一个维度
for l in layer_image:
l_images.append(torch.unsqueeze(l, 0))
# 将每个图层图像添加到图层图像列表中,并在第 0 维增加一个维度
m = tensor2pil(l)
# 将图层图像从张量转换为 PIL 图像
if m.mode == 'RGBA':
l_masks.append(m.split()[-1])
# 如果图层图像是 RGBA 模式,将 Alpha 通道添加到图层掩码列表中
else:
l_masks.append(Image.new('L', m.size, 'white'))
# 否则,创建一个白色的 L 模式图像作为掩码,并添加到图层掩码列表中
if layer_mask is not None:
if layer_mask.dim() == 2:
layer_mask = torch.unsqueeze(layer_mask, 0)
# 如果提供了图层掩码并且其维度为 2,增加一个维度
l_masks = []
for m in layer_mask:
if invert_mask:
m = 1 - m
# 如果需要反转掩码,将掩码取反
l_masks.append(tensor2pil(torch.unsqueeze(m, 0)).convert('L'))
# 将掩码从张量转换为 PIL 图像并添加到图层掩码列表中
max_batch = max(len(b_images), len(l_images), len(l_masks))
# 计算批次的最大长度
for i in range(max_batch):
background_image = b_images[i] if i < len(b_images) else b_images[-1]
# 获取当前批次的背景图像
layer_image = l_images[i] if i < len(l_images) else l_images[-1]
# 获取当前批次的图层图像
_mask = l_masks[i] if i < len(l_masks) else l_masks[-1]
# 获取当前批次的图层掩码
_canvas = tensor2pil(background_image).convert('RGB')
# 将背景图像转换为 RGB 模式的 PIL 图像
_layer = tensor2pil(layer_image).convert('RGB')
# 将图层图像转换为 RGB 模式的 PIL 图像
if _mask.size != _layer.size:
_mask = Image.new('L', _layer.size, 'white')
# 如果掩码的大小与图层图像不同,创建一个白色的 L 模式掩码
log(f"Warning: {NODE_NAME} mask mismatch, dropped!", message_type='warning')
# 记录掩码大小不匹配的警告
# 合成图层
_comp = chop_image(_canvas, _layer, blend_mode, opacity)
# 根据混合模式和透明度将图层图像合成到背景图像上
_canvas.paste(_comp, mask=_mask)
# 使用掩码将合成结果粘贴到背景图像上
ret_images.append(pil2tensor(_canvas))
# 将合成后的图像转换回张量并添加到返回图像列表中
log(f"{NODE_NAME} Processed {len(ret_images)} image(s).", message_type='finish')
# 记录处理的图像数量
return (torch.cat(ret_images, dim=0),)
# 返回连接后的结果图像张量
主要步骤和功能
-
类定义和初始化:
ImageBlend
类用于图像混合操作,初始化函数为空。
-
定义输入类型:
INPUT_TYPES
类方法定义了所需的输入类型,包括背景图像、图层图像、反转掩码选项、混合模式和透明度,以及可选的图层掩码。
-
定义返回类型:
RETURN_TYPES
和RETURN_NAMES
定义了返回类型和名称为图像。FUNCTION
定义了主要功能函数为image_blend
。
-
图像混合方法:
image_blend
方法是核心功能,处理图像混合逻辑。- 将背景图像、图层图像和掩码从张量转换为 PIL 图像,并根据输入参数进行图像混合。
- 使用
chop_image
函数根据混合模式和透明度将图层图像合成到背景图像上,并使用掩码粘贴到背景图像上。 - 最后,将合成后的图像转换回张量并返回。
-
节点映射:
NODE_CLASS_MAPPINGS
和NODE_DISPLAY_NAME_MAPPINGS
将节点名称和显示名称映射到ImageBlend
类。
分段解释
1. 引入和类定义
```python
from .imagefunc import *
# 从当前目录中的 imagefunc 模块导入所有函数和变量NODE_NAME = 'ImageBlend'
# 定义节点名称为 'ImageBlend'class ImageBlend:
# 定义一个名为 ImageBlend 的类def __init__(self):
# 初始化函数
pass
```
这段代码引入了当前目录中的 `imagefunc` 模块中的所有函数和变量,并定义了一个名为 `ImageBlend` 的类。`NODE_NAME` 用于指定节点的名称,`__init__` 初始化函数为空,不执行任何操作。
2. 输入类型定义
```python
@classmethod
def INPUT_TYPES(self):
# 定义一个类方法 INPUT_TYPES,返回输入参数的类型
return {
"required": {
"background_image": ("IMAGE", ), # 背景图像
"layer_image": ("IMAGE",), # 图层图像
"invert_mask": ("BOOLEAN", {"default": True}), # 反转掩码,默认值为 True
"blend_mode": (chop_mode,), # 混合模式
"opacity": ("INT", {"default": 100, "min": 0, "max": 100, "step": 1}), # 透明度,默认值为 100,范围从 0 到 100,步长为 1
},
"optional": {
"layer_mask": ("MASK",), # 可选的图层掩码
}
}
```
这段代码定义了一个类方法 `INPUT_TYPES`,用于指定 `ImageBlend` 节点所需的输入类型。包括必需的参数(背景图像、图层图像、反转掩码选项、混合模式和透明度)和可选的参数(图层掩码)。
3. 返回类型和类别定义
```python
RETURN_TYPES = ("IMAGE",)
# 返回类型为图像
RETURN_NAMES = ("image",)
# 返回的名称为图像
FUNCTION = 'image_blend'
```
这段代码定义了 `ImageBlend` 节点的返回类型和名称。`RETURN_TYPES` 和 `RETURN_NAMES` 分别指定了返回的类型和名称为图像。`FUNCTION` 指定了主要功能函数为 `image_blend`
4. 图像混合方法
```python
def image_blend(self, background_image, layer_image, invert_mask, blend_mode, opacity, layer_mask=None):
# 定义图像混合的主要功能
b_images = []
# 初始化背景图像列表
l_images = []
# 初始化图层图像列表
l_masks = []
# 初始化图层掩码列表
ret_images = []
# 初始化返回图像列表
```
`image_blend` 方法是 `ImageBlend` 类的核心功能,用于处理图像混合逻辑。首先初始化了背景图像列表、图层图像列表、图层掩码列表和返回图像列表。
### 5. 处理背景图像和图层图像
```python
for b in background_image:
b_images.append(torch.unsqueeze(b, 0))
# 将每个背景图像添加到背景图像列表中,并在第 0 维增加一个维度
for l in layer_image:
l_images.append(torch.unsqueeze(l, 0))
# 将每个图层图像添加到图层图像列表中,并在第 0 维增加一个维度
m = tensor2pil(l)
# 将图层图像从张量转换为 PIL 图像
if m.mode == 'RGBA':
l_masks.append(m.split()[-1])
# 如果图层图像是 RGBA 模式,将 Alpha 通道添加到图层掩码列表中
else:
l_masks.append(Image.new('L', m.size, 'white'))
# 否则,创建一个白色的 L 模式图像作为掩码,并添加到图层掩码列表中
```
这段代码将背景图像和图层图像分别添加到各自的列表中,并在第 0 维增加一个维度。同时,如果图层图像是 RGBA 模式,将其 Alpha 通道作为掩码添加到 `l_masks` 列表中,否则创建一个白色的 L 模式图像作为掩码。
6. 处理图层掩码
```python
if layer_mask is not None:
if layer_mask.dim() == 2:
layer_mask = torch.unsqueeze(layer_mask, 0)
# 如果提供了图层掩码并且其维度为 2,增加一个维度
l_masks = []
for m in layer_mask:
if invert_mask:
m = 1 - m
# 如果需要反转掩码,将掩码取反
l_masks.append(tensor2pil(torch.unsqueeze(m, 0)).convert('L'))
# 将掩码从张量转换为 PIL 图像并添加到图层掩码列表中
```
这段代码检查是否提供了图层掩码。如果提供了并且其维度为 2,则增加一个维度。然后,根据 `invert_mask` 参数决定是否反转掩码,并将掩码从张量转换为 PIL 图像,添加到 `l_masks` 列表中。
7. 处理每批图像
```python
max_batch = max(len(b_images), len(l_images), len(l_masks))
# 计算批次的最大长度for i in range(max_batch):
background_image = b_images[i] if i < len(b_images) else b_images[-1]
# 获取当前批次的背景图像
layer_image = l_images[i] if i < len(l_images) else l_images[-1]
# 获取当前批次的图层图像
_mask = l_masks[i] if i < len(l_masks) else l_masks[-1]
# 获取当前批次的图层掩码
```
这段代码计算批次的最大长度,并在循环中处理每批图像。根据索引获取当前批次的背景图像、图层图像和图层掩码。
8. 图像合成和掩码应用
```python
_canvas = tensor2pil(background_image).convert('RGB')
# 将背景图像转换为 RGB 模式的 PIL 图像
_layer = tensor2pil(layer_image).convert('RGB')
# 将图层图像转换为 RGB 模式的 PIL 图像if _mask.size != _layer.size:
_mask = Image.new('L', _layer.size, 'white')
# 如果掩码的大小与图层图像不同,创建一个白色的 L 模式掩码
log(f"Warning: {NODE_NAME} mask mismatch, dropped!", message_type='warning')
# 记录掩码大小不匹配的警告# 合成图层
_comp = chop_image(_canvas, _layer, blend_mode, opacity)
# 根据混合模式和透明度将图层图像合成到背景图像上
_canvas.paste(_comp, mask=_mask)
# 使用掩码将合成结果粘贴到背景图像上ret_images.append(pil2tensor(_canvas))
# 将合成后的图像转换回张量并添加到返回图像列表中
```
这段代码将背景图像和图层图像转换为 RGB 模式的 PIL 图像。如果掩码的大小与图层图像不同,创建一个白色的 L 模式掩码,并记录警告。然后,使用 `chop_image` 函数根据混合模式和透明度将图层图像合成到背景图像上,并使用掩码将合成结果粘贴到背景图像上。最后,将合成后的图像转换回张量并添加到返回图像列表中。
9. 返回结果
```python
log(f"{NODE_NAME} Processed {len(ret_images)} image(s).", message_type='finish')
# 记录处理的图像数量
return (torch.cat(ret_images, dim=0),)
# 返回连接后的结果图像张量
```
这段代码记录处理的图像数量,并返回连接后的结果图像张量。
总结
这个 `ImageBlend` 类主要用于在图像处理工作流中,将背景图像和图层图像根据指定的混合模式和透明度进行混合,并返回合成后的图像。通过详细注释每段代码,可以更清晰地理解每一步的具体作用和处理逻辑。