Files
CavinHuang-comfyui-nodes-docs/docs/MiDaS Mask Image.md
2024-05-26 20:35:16 +08:00

7.5 KiB

Documentation

该节点使用MiDaS模型从图像中估计深度,并根据用户输入移除背景或前景,增强图像的视觉清晰度和焦点。

Input types

Required

  • image
    • 源图像,从中估计深度并移除背景或前景。
    • Comfy dtype: IMAGE
    • Python dtype: PIL.Image
  • midas_model
    • 指定用于深度估计的MiDaS模型的大小,较大的模型通常能提供更准确的结果,但需要更多的计算资源。
    • Comfy dtype: COMBO[ ['DPT_Large', 'DPT_Hybrid', 'DPT_Small' ]]
    • Python dtype: str
  • remove
    • 指示应从图像中移除背景还是前景,影响输出的构图。
    • Comfy dtype: COMBO[ ['background', 'foreground' ]]
    • Python dtype: str

Optional

  • use_cpu
    • 决定是否使用CPU进行处理。卸载到GPU通常更快,但需要兼容的硬件。
    • Comfy dtype: COMBO[ ['false', 'true' ]]
    • Python dtype: str
  • threshold
    • 对深度图应用阈值,可以细化移除元素与图像其余部分的分离。
    • Comfy dtype: COMBO[ ['false', 'true' ]]
    • Python dtype: str
  • threshold_low
    • 设置深度值阈值范围的下限,影响分割的精度。
    • Comfy dtype: FLOAT
    • Python dtype: float
  • threshold_mid
    • 定义阈值范围的中点,进一步调整保留和移除的图像部分之间的过渡。
    • Comfy dtype: FLOAT
    • Python dtype: float
  • threshold_high
    • 建立阈值范围的上限,这可以影响移除过程中图像最深处的处理方式。
    • Comfy dtype: FLOAT
    • Python dtype: float
  • smoothing
    • 控制应用于深度图的平滑程度,这有助于减少最终输出中的噪声和伪影。
    • Comfy dtype: FLOAT
    • Python dtype: float
  • background_red
    • 设置用于填充移除区域的背景颜色的红色分量,影响结果图像的视觉外观。
    • Comfy dtype: INT
    • Python dtype: int
  • background_green
    • 确定背景颜色的绿色分量,有助于构成移除元素区域的整体色彩方案。
    • Comfy dtype: INT
    • Python dtype: int
  • background_blue
    • 指定背景颜色的蓝色分量,用于在编辑图像中实现期望的色彩平衡。
    • Comfy dtype: INT
    • Python dtype: int

Output types

  • result_image
    • 处理后的图像,已移除指定的背景或前景元素,可供进一步使用或分析。
    • Comfy dtype: IMAGE
    • Python dtype: PIL.Image
  • depth_map
    • 从输入图像派生出的深度图,视觉上表示场景中的估计距离,并在内部用于移除过程。
    • Comfy dtype: IMAGE
    • Python dtype: PIL.Image

Usage tips

  • Infra type: GPU

Source code

class MiDaS_Background_Foreground_Removal:

    def __init__(self):
        self.midas_dir = os.path.join(MODELS_DIR, 'midas')

    @classmethod
    def INPUT_TYPES(cls):
        return {'required': {'image': ('IMAGE',), 'use_cpu': (['false', 'true'],), 'midas_model': (['DPT_Large', 'DPT_Hybrid', 'DPT_Small'],), 'remove': (['background', 'foregroud'],), 'threshold': (['false', 'true'],), 'threshold_low': ('FLOAT', {'default': 10, 'min': 0, 'max': 255, 'step': 1}), 'threshold_mid': ('FLOAT', {'default': 200, 'min': 0, 'max': 255, 'step': 1}), 'threshold_high': ('FLOAT', {'default': 210, 'min': 0, 'max': 255, 'step': 1}), 'smoothing': ('FLOAT', {'default': 0.25, 'min': 0.0, 'max': 16.0, 'step': 0.01}), 'background_red': ('INT', {'default': 0, 'min': 0, 'max': 255, 'step': 1}), 'background_green': ('INT', {'default': 0, 'min': 0, 'max': 255, 'step': 1}), 'background_blue': ('INT', {'default': 0, 'min': 0, 'max': 255, 'step': 1})}}
    RETURN_TYPES = ('IMAGE', 'IMAGE')
    FUNCTION = 'midas_remove'
    CATEGORY = 'WAS Suite/Image/AI'

    def midas_remove(self, image, midas_model, use_cpu='false', remove='background', threshold='false', threshold_low=0, threshold_mid=127, threshold_high=255, smoothing=0.25, background_red=0, background_green=0, background_blue=0):
        global MIDAS_INSTALLED
        if not MIDAS_INSTALLED:
            self.install_midas()
        import cv2 as cv
        i = 255.0 * image.cpu().numpy().squeeze()
        img = i
        img_original = tensor2pil(image).convert('RGB')
        cstr('Downloading and loading MiDaS Model...').msg.print()
        torch.hub.set_dir(self.midas_dir)
        midas = torch.hub.load('intel-isl/MiDaS', midas_model, trust_repo=True)
        device = torch.device('cuda') if torch.cuda.is_available() and use_cpu == 'false' else torch.device('cpu')
        cstr(f'MiDaS is using device: {device}').msg.print()
        midas.to(device).eval()
        midas_transforms = torch.hub.load('intel-isl/MiDaS', 'transforms')
        if midas_model == 'DPT_Large' or midas_model == 'DPT_Hybrid':
            transform = midas_transforms.dpt_transform
        else:
            transform = midas_transforms.small_transform
        img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
        input_batch = transform(img).to(device)
        cstr('Approximating depth from image.').msg.print()
        with torch.no_grad():
            prediction = midas(input_batch)
            prediction = torch.nn.functional.interpolate(prediction.unsqueeze(1), size=img.shape[:2], mode='bicubic', align_corners=False).squeeze()
        if remove == 'foreground':
            depth = 255 - prediction.cpu().numpy().astype(np.uint8)
            depth = depth.astype(np.float32)
        else:
            depth = prediction.cpu().numpy().astype(np.float32)
        depth = depth * 255 / np.max(depth) / 255
        depth = Image.fromarray(np.uint8(depth * 255))
        if threshold == 'true':
            levels = self.AdjustLevels(threshold_low, threshold_mid, threshold_high)
            depth = levels.adjust(depth.convert('RGB')).convert('L')
        if smoothing > 0:
            depth = depth.filter(ImageFilter.GaussianBlur(radius=smoothing))
        depth = depth.resize(img_original.size).convert('L')
        background_red = int(background_red) if isinstance(background_red, (int, float)) else 0
        background_green = int(background_green) if isinstance(background_green, (int, float)) else 0
        background_blue = int(background_blue) if isinstance(background_blue, (int, float)) else 0
        background_color = (background_red, background_green, background_blue)
        background = Image.new(mode='RGB', size=img_original.size, color=background_color)
        result_img = Image.composite(img_original, background, depth)
        del midas, device, midas_transforms
        del transform, img, img_original, input_batch, prediction
        return (pil2tensor(result_img), pil2tensor(depth.convert('RGB')))

    class AdjustLevels:

        def __init__(self, min_level, mid_level, max_level):
            self.min_level = min_level
            self.mid_level = mid_level
            self.max_level = max_level

        def adjust(self, im):
            im_arr = np.array(im)
            im_arr[im_arr < self.min_level] = self.min_level
            im_arr = (im_arr - self.min_level) * (255 / (self.max_level - self.min_level))
            im_arr[im_arr < 0] = 0
            im_arr[im_arr > 255] = 255
            im_arr = im_arr.astype(np.uint8)
            im = Image.fromarray(im_arr)
            im = ImageOps.autocontrast(im, cutoff=self.max_level)
            return im

    def install_midas(self):
        global MIDAS_INSTALLED
        if 'timm' not in packages():
            install_package('timm')
        MIDAS_INSTALLED = True