9.5 KiB
9.5 KiB
Documentation
- Class name: MakeTileSEGS
- Category: ImpactPack/__for_testing
- Output node: False
- Repo Ref: https://github.com/ltdrdata/ComfyUI-Impact-Pack.git
MakeTileSEGS节点旨在根据指定参数处理和分割图像成块。它智能地处理重叠区域,并应用过滤器以包含或排除某些段,确保一个无缝的分割过程,满足高级图像分析的需求。
Input types
Required
- images
- 输入图像参数对于节点的操作至关重要,因为它作为分割的原始数据。它直接影响节点的执行和生成的段的质量。
- Comfy dtype: IMAGE
- Python dtype: torch.Tensor
- bbox_size
- bbox_size参数定义了用于图像分割的边界框大小,这对于确定每个块的尺寸至关重要。它在分割过程中和最终输出中扮演着重要角色。
- Comfy dtype: INT
- Python dtype: int
- crop_factor
- crop_factor参数用于调整裁剪区域相对于边界框的大小,影响每个段中捕获的细节。这是微调分割输出的重要参数。
- Comfy dtype: FLOAT
- Python dtype: float
- min_overlap
- min_overlap参数指定相邻块之间的最小重叠量,确保段之间的平滑过渡。这对于保持分割区域的连续性至关重要。
- Comfy dtype: INT
- Python dtype: int
- filter_segs_dilation
- filter_segs_dilation参数控制分割掩码的膨胀,允许调整分割区域的大小和形状。它是细化分割细节的关键。
- Comfy dtype: INT
- Python dtype: int
Optional
- mask_irregularity
- mask_irregularity参数在分割掩码中引入不规则性,这对于需要非均匀分割的某些应用非常有用。它为分割过程增加了可变性。
- Comfy dtype: FLOAT
- Python dtype: float
- irregular_mask_mode
- irregular_mask_mode参数确定用于在掩码中生成不规则性的方法是,提供不同质量和速度级别的掩码生成过程。
- Comfy dtype: COMBO['Reuse fast', 'Reuse quality', 'All random fast', 'All random quality']
- Python dtype: str
- filter_in_segs_opt
- filter_in_segs_opt参数允许在分割过程中包含特定段,提供一种专注于图像中感兴趣区域的方法。
- Comfy dtype: SEGS
- Python dtype: List[SEG]
- filter_out_segs_opt
- filter_out_segs_opt参数使从分割过程中排除某些段成为可能,允许从最终分割中移除不需要的区域。
- Comfy dtype: SEGS
- Python dtype: List[SEG]
Output types
- result
- result参数封装了分割过程的输出,提供了分割图像块的详细和结构化表示。
- Comfy dtype: SEGS
- Python dtype: Tuple[int, List[SEG]]
Usage tips
- Infra type: CPU
Source code
class MakeTileSEGS:
@classmethod
def INPUT_TYPES(s):
return {'required': {'images': ('IMAGE',), 'bbox_size': ('INT', {'default': 512, 'min': 64, 'max': 4096, 'step': 8}), 'crop_factor': ('FLOAT', {'default': 3.0, 'min': 1.0, 'max': 10, 'step': 0.1}), 'min_overlap': ('INT', {'default': 5, 'min': 0, 'max': 512, 'step': 1}), 'filter_segs_dilation': ('INT', {'default': 20, 'min': -255, 'max': 255, 'step': 1}), 'mask_irregularity': ('FLOAT', {'default': 0, 'min': 0, 'max': 1.0, 'step': 0.01}), 'irregular_mask_mode': (['Reuse fast', 'Reuse quality', 'All random fast', 'All random quality'],)}, 'optional': {'filter_in_segs_opt': ('SEGS',), 'filter_out_segs_opt': ('SEGS',)}}
RETURN_TYPES = ('SEGS',)
FUNCTION = 'doit'
CATEGORY = 'ImpactPack/__for_testing'
def doit(self, images, bbox_size, crop_factor, min_overlap, filter_segs_dilation, mask_irregularity=0, irregular_mask_mode='Reuse fast', filter_in_segs_opt=None, filter_out_segs_opt=None):
if bbox_size <= 2 * min_overlap:
new_min_overlap = bbox_size / 2
print(f'[MakeTileSEGS] min_overlap should be greater than bbox_size. (value changed: {min_overlap} => {new_min_overlap})')
min_overlap = new_min_overlap
(_, ih, iw, _) = images.size()
mask_cache = None
mask_quality = 512
if mask_irregularity > 0:
if irregular_mask_mode == 'Reuse fast':
mask_quality = 128
mask_cache = np.zeros((128, 128)).astype(np.float32)
core.random_mask(mask_cache, (0, 0, 128, 128), factor=mask_irregularity, size=mask_quality)
elif irregular_mask_mode == 'Reuse quality':
mask_quality = 512
mask_cache = np.zeros((512, 512)).astype(np.float32)
core.random_mask(mask_cache, (0, 0, 512, 512), factor=mask_irregularity, size=mask_quality)
elif irregular_mask_mode == 'All random fast':
mask_quality = 512
if mask_irregularity > 0:
compensate = max(6, int(mask_quality * mask_irregularity / 4))
min_overlap += compensate
bbox_size += compensate * 2
if filter_out_segs_opt is not None:
exclusion_mask = core.segs_to_combined_mask(filter_out_segs_opt)
exclusion_mask = utils.make_3d_mask(exclusion_mask)
exclusion_mask = utils.resize_mask(exclusion_mask, (ih, iw))
exclusion_mask = dilate_mask(exclusion_mask.cpu().numpy(), filter_segs_dilation)
else:
exclusion_mask = None
if filter_in_segs_opt is not None:
and_mask = core.segs_to_combined_mask(filter_in_segs_opt)
and_mask = utils.make_3d_mask(and_mask)
and_mask = utils.resize_mask(and_mask, (ih, iw))
and_mask = dilate_mask(and_mask.cpu().numpy(), filter_segs_dilation)
(a, b) = core.mask_to_segs(and_mask, True, 1.0, False, 0)
if len(b) == 0:
return ((a, b),)
(start_x, start_y, c, d) = b[0].crop_region
w = c - start_x
h = d - start_y
else:
start_x = 0
start_y = 0
(h, w) = (ih, iw)
and_mask = None
if bbox_size > h or bbox_size > w:
new_bbox_size = min(bbox_size, min(w, h))
print(f'[MaskTileSEGS] bbox_size is greater than resolution (value changed: {bbox_size} => {new_bbox_size}')
bbox_size = new_bbox_size
n_horizontal = math.ceil(w / (bbox_size - min_overlap))
n_vertical = math.ceil(h / (bbox_size - min_overlap))
w_overlap_sum = bbox_size * n_horizontal - w
if w_overlap_sum < 0:
n_horizontal += 1
w_overlap_sum = bbox_size * n_horizontal - w
w_overlap_size = 0 if n_horizontal == 1 else int(w_overlap_sum / (n_horizontal - 1))
h_overlap_sum = bbox_size * n_vertical - h
if h_overlap_sum < 0:
n_vertical += 1
h_overlap_sum = bbox_size * n_vertical - h
h_overlap_size = 0 if n_vertical == 1 else int(h_overlap_sum / (n_vertical - 1))
new_segs = []
if w_overlap_size == bbox_size:
n_horizontal = 1
if h_overlap_size == bbox_size:
n_vertical = 1
y = start_y
for j in range(0, n_vertical):
x = start_x
for i in range(0, n_horizontal):
x1 = x
y1 = y
if x + bbox_size < iw - 1:
x2 = x + bbox_size
else:
x2 = iw
x1 = iw - bbox_size
if y + bbox_size < ih - 1:
y2 = y + bbox_size
else:
y2 = ih
y1 = ih - bbox_size
bbox = (x1, y1, x2, y2)
crop_region = make_crop_region(iw, ih, bbox, crop_factor)
(cx1, cy1, cx2, cy2) = crop_region
mask = np.zeros((cy2 - cy1, cx2 - cx1)).astype(np.float32)
rel_left = x1 - cx1
rel_top = y1 - cy1
rel_right = x2 - cx1
rel_bot = y2 - cy1
if mask_irregularity > 0:
if mask_cache is not None:
core.adaptive_mask_paste(mask, mask_cache, (rel_left, rel_top, rel_right, rel_bot))
else:
core.random_mask(mask, (rel_left, rel_top, rel_right, rel_bot), factor=mask_irregularity, size=mask_quality)
if rel_left == 0:
pad = int((x2 - x1) / 8)
mask[rel_top:rel_bot, :pad] = 1.0
if rel_top == 0:
pad = int((y2 - y1) / 8)
mask[:pad, rel_left:rel_right] = 1.0
if rel_right == mask.shape[1]:
pad = int((x2 - x1) / 8)
mask[rel_top:rel_bot, -pad:] = 1.0
if rel_bot == mask.shape[0]:
pad = int((y2 - y1) / 8)
mask[-pad:, rel_left:rel_right] = 1.0
else:
mask[rel_top:rel_bot, rel_left:rel_right] = 1.0
mask = torch.tensor(mask)
if exclusion_mask is not None:
exclusion_mask_cropped = exclusion_mask[cy1:cy2, cx1:cx2]
mask[exclusion_mask_cropped != 0] = 0.0
if and_mask is not None:
and_mask_cropped = and_mask[cy1:cy2, cx1:cx2]
mask[and_mask_cropped == 0] = 0.0
is_mask_zero = torch.all(mask == 0.0).item()
if not is_mask_zero:
item = SEG(None, mask.numpy(), 1.0, crop_region, bbox, '', None)
new_segs.append(item)
x += bbox_size - w_overlap_size
y += bbox_size - h_overlap_size
res = ((ih, iw), new_segs)
return (res,)