Automatically calculates a mask based on the text prompt
| 111 | return t1, t2 |
| 112 | |
| 113 | class ClipSegNode: |
| 114 | """ |
| 115 | Automatically calculates a mask based on the text prompt |
| 116 | """ |
| 117 | def __init__(self): |
| 118 | pass |
| 119 | |
| 120 | @classmethod |
| 121 | def INPUT_TYPES(cls): |
| 122 | return { |
| 123 | "required": { |
| 124 | "image": ("IMAGE",), |
| 125 | "prompt": ("STRING", {"multiline": True}), |
| 126 | "negative_prompt": ("STRING", {"multiline": True}), |
| 127 | "precision": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}), |
| 128 | "normalize": (["no", "yes"],), |
| 129 | }, |
| 130 | } |
| 131 | |
| 132 | RETURN_TYPES = ("IMAGE","IMAGE",) |
| 133 | RETURN_NAMES = ("thresholded_mask", "raw_mask",) |
| 134 | FUNCTION = "get_mask" |
| 135 | |
| 136 | CATEGORY = "Masquerade Nodes" |
| 137 | |
| 138 | def get_mask(self, image, prompt, negative_prompt, precision, normalize): |
| 139 | |
| 140 | model = self.load_model() |
| 141 | image = tensor2rgb(image) |
| 142 | B, H, W, _ = image.shape |
| 143 | # clipseg only works on square images, so we'll just use the larger dimension |
| 144 | # TODO - Should we pad instead of resize? |
| 145 | used_dim = max(W, H) |
| 146 | |
| 147 | transform = transforms.Compose([ |
| 148 | transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), |
| 149 | transforms.Resize((used_dim, used_dim), antialias=True) ]) |
| 150 | img = transform(image.permute(0, 3, 1, 2)) |
| 151 | |
| 152 | prompts = prompt.split(DELIMITER) |
| 153 | negative_prompts = negative_prompt.split(DELIMITER) if negative_prompt != '' else [] |
| 154 | with torch.no_grad(): |
| 155 | # Optimize me: Could do positive and negative prompts as part of one batch |
| 156 | dup_prompts = [item for item in prompts for _ in range(B)] |
| 157 | preds = model(img.repeat(len(prompts), 1, 1, 1), dup_prompts)[0] |
| 158 | dup_neg_prompts = [item for item in negative_prompts for _ in range(B)] |
| 159 | negative_preds = model(img.repeat(len(negative_prompts), 1, 1, 1), dup_neg_prompts)[0] if len(negative_prompts) > 0 else None |
| 160 | |
| 161 | preds = torch.nn.functional.interpolate(preds, size=(H, W), mode='nearest') |
| 162 | preds = torch.sigmoid(preds) |
| 163 | preds = preds.reshape(len(prompts), B, H, W) |
| 164 | mask = torch.max(preds, dim=0).values |
| 165 | |
| 166 | if len(negative_prompts) > 0: |
| 167 | negative_preds = torch.nn.functional.interpolate(negative_preds, size=(H, W), mode='nearest') |
| 168 | negative_preds = torch.sigmoid(negative_preds) |
| 169 | negative_preds = negative_preds.reshape(len(negative_prompts), B, H, W) |
| 170 | mask_neg = torch.max(negative_preds, dim=0).values |
nothing calls this directly
no outgoing calls
no test coverage detected