Spaces:
Running
on
Zero
Running
on
Zero
| import torch | |
| from PIL import Image, ImageFilter, ImageOps | |
| from comfy.utils import common_upscale | |
| from .utils.image_convert import np2tensor, tensor2mask | |
| from .utils.mask_utils import blur_mask, combine_mask, expand_mask, fill_holes, grow_mask, invert_mask | |
| _CATEGORY = 'fnodes/masks' | |
| class OutlineMask: | |
| def INPUT_TYPES(cls): | |
| return { | |
| 'required': { | |
| 'mask': ('MASK',), | |
| 'outline_width': ( | |
| 'INT', | |
| {'default': 10, 'min': 1, 'max': 16384, 'step': 1}, | |
| ), | |
| 'tapered_corners': ('BOOLEAN', {'default': True}), | |
| } | |
| } | |
| RETURN_TYPES = ('MASK',) | |
| FUNCTION = 'execute' | |
| CATEGORY = _CATEGORY | |
| DESCRIPTION = '给遮罩添加轮廓线' | |
| def execute(self, mask, outline_width, tapered_corners): | |
| m1 = grow_mask(mask, outline_width, tapered_corners) | |
| m2 = grow_mask(mask, -outline_width, tapered_corners) | |
| m3 = combine_mask(m1, m2, 0, 0) | |
| return (m3,) | |
| class CreateBlurredEdgeMask: | |
| def INPUT_TYPES(cls): | |
| return { | |
| 'required': { | |
| 'width': ('INT', {'default': 1024, 'min': 0, 'max': 14096, 'step': 1}), | |
| 'height': ('INT', {'default': 1024, 'min': 0, 'max': 14096, 'step': 1}), | |
| 'border': ('INT', {'default': 0, 'min': 0, 'max': 4096, 'step': 1}), | |
| 'border_percent': ( | |
| 'FLOAT', | |
| {'default': 0.05, 'min': 0.0, 'max': 2.0, 'step': 0.01}, | |
| ), | |
| 'blur_radius': ( | |
| 'INT', | |
| {'default': 10, 'min': 0, 'max': 4096, 'step': 1}, | |
| ), | |
| 'blur_radius_percent': ( | |
| 'FLOAT', | |
| {'default': 0.00, 'min': 0.0, 'max': 2.0, 'step': 0.01}, | |
| ), | |
| }, | |
| 'optional': { | |
| 'image': ('IMAGE', {'tooltips': '如果未提供图像,将使用输入的宽度和高度创建一个白色图像。'}), | |
| }, | |
| } | |
| RETURN_TYPES = ('MASK',) | |
| FUNCTION = 'execute' | |
| CATEGORY = _CATEGORY | |
| DESCRIPTION = '根据指定图片创建模糊遮罩' | |
| def execute(self, width, height, border, border_percent, blur_radius, blur_radius_percent, image=None): | |
| if image is not None: | |
| _, height, width, _ = image.shape | |
| # 计算边框宽度 | |
| border_width = int(min(width, height) * border_percent + border) | |
| # 计算内部图像的尺寸 | |
| inner_width = width - 2 * border_width | |
| inner_height = height - 2 * border_width | |
| # 创建内部白色图像 | |
| inner_image = Image.new('RGB', (inner_width, inner_height), 'white') | |
| # 扩展图像,添加黑色边框 | |
| image_with_border = ImageOps.expand(inner_image, border=border_width, fill='black') | |
| # 计算模糊半径 | |
| blur_radius = int(min(width, height) * blur_radius_percent + blur_radius) | |
| # 应用高斯模糊 | |
| blurred_image = image_with_border.filter(ImageFilter.GaussianBlur(radius=blur_radius)) | |
| # 转换为张量 | |
| blurred_tensor = np2tensor(blurred_image) | |
| blurred_image = blurred_tensor.unsqueeze(0) | |
| return (tensor2mask(blurred_image),) | |
| class MaskChange: | |
| def INPUT_TYPES(cls): | |
| return { | |
| 'required': { | |
| 'mask': ('MASK',), | |
| 'grow': ('INT', {'default': 0, 'min': -4096, 'max': 4096, 'step': 1}), | |
| 'grow_percent': ( | |
| 'FLOAT', | |
| {'default': 0.00, 'min': 0.00, 'max': 2.0, 'step': 0.01}, | |
| ), | |
| 'grow_tapered': ('BOOLEAN', {'default': False}), | |
| 'blur': ('INT', {'default': 0, 'min': 0, 'max': 4096, 'step': 1}), | |
| 'fill': ('BOOLEAN', {'default': False}), | |
| }, | |
| } | |
| RETURN_TYPES = ('MASK', 'MASK') | |
| RETURN_NAMES = ('mask', 'inverted_mask') | |
| FUNCTION = 'execute' | |
| CATEGORY = _CATEGORY | |
| DESCRIPTION = '修改和处理遮罩' | |
| def execute(self, mask, grow, grow_percent, grow_tapered, blur, fill): | |
| grow_count = int(grow_percent * max(mask.shape)) + grow | |
| if grow_count > 0: | |
| mask = expand_mask(mask, grow_count, grow_tapered) | |
| if fill: | |
| mask = fill_holes(mask) | |
| if blur > 0: | |
| mask = blur_mask(mask, blur) | |
| # mask = mask.squeeze(0).unsqueeze(-1) | |
| return (mask, invert_mask(mask)) | |
| class Depth2Mask: | |
| def __init__(self): | |
| pass | |
| def INPUT_TYPES(cls): | |
| return { | |
| 'required': { | |
| 'image_depth': ('IMAGE',), | |
| 'depth': ( | |
| 'FLOAT', | |
| {'default': 0.2, 'min': 0.0, 'max': 1.0, 'step': 0.01, 'round': 0.001, 'display': 'number'}, | |
| ), | |
| }, | |
| } | |
| RETURN_TYPES = ('MASK', 'MASK') | |
| RETURN_NAMES = ('mask', 'mask_inverted') | |
| FUNCTION = 'execute' | |
| CATEGORY = _CATEGORY | |
| DESCRIPTION = '将深度图像转换为遮罩' | |
| def execute(self, image_depth, depth): | |
| def upscale(image, upscale_method, width, height): | |
| samples = image.movedim(-1, 1) | |
| s = common_upscale(samples, width, height, upscale_method, 'disabled') | |
| s = s.movedim(1, -1) | |
| return (s,) | |
| bs, height, width = image_depth.size()[0], image_depth.size()[1], image_depth.size()[2] | |
| mask1 = torch.zeros((bs, height, width)) | |
| image_depth = upscale(image_depth, 'lanczos', width, height)[0] | |
| mask1 = (image_depth[..., 0] < depth).float() | |
| return mask1, 1.0 - mask1 | |
| MASK_CLASS_MAPPINGS = { | |
| 'OutlineMask-': OutlineMask, | |
| 'CreateBlurredEdgeMask-': CreateBlurredEdgeMask, | |
| 'MaskChange-': MaskChange, | |
| 'Depth2Mask-': Depth2Mask, | |
| } | |
| MASK_NAME_MAPPINGS = { | |
| 'OutlineMask-': 'Outline Mask', | |
| 'CreateBlurredEdgeMask-': 'Create Blurred Edge Mask', | |
| 'MaskChange-': 'Mask Change', | |
| 'Depth2Mask-': 'Depth to Mask', | |
| } | |