Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
432cb4d146 | ||
|
|
69a944969c | ||
|
|
240209bc25 | ||
|
|
5c7bfe05a1 | ||
|
|
758b0069e9 | ||
|
|
ef6e78ba01 |
+340
-6
@@ -1,4 +1,3 @@
|
||||
from PIL import Image, ImageFilter, ImageOps
|
||||
import os
|
||||
import torch
|
||||
import numpy as np
|
||||
@@ -22,8 +21,10 @@ def update_package_list():
|
||||
global package_list
|
||||
package_list = [r.decode().split('==')[0] for r in subprocess.check_output([sys.executable, '-m', 'pip', 'freeze']).split()]
|
||||
|
||||
def ensure_package(package_name, import_path):
|
||||
def ensure_package(package_name, import_path=None):
|
||||
global package_list
|
||||
if import_path == None:
|
||||
import_path = package_name
|
||||
if package_list == None:
|
||||
update_package_list()
|
||||
|
||||
@@ -110,6 +111,9 @@ def tensors2common(t1: torch.Tensor, t2: torch.Tensor) -> (torch.Tensor, torch.T
|
||||
return t1, t2
|
||||
|
||||
class ClipSegNode:
|
||||
"""
|
||||
Automatically calculates a mask based on the text prompt
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -126,6 +130,7 @@ class ClipSegNode:
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE","IMAGE",)
|
||||
RETURN_NAMES = ("thresholded_mask", "raw_mask",)
|
||||
FUNCTION = "get_mask"
|
||||
|
||||
CATEGORY = "Masquerade Nodes"
|
||||
@@ -311,7 +316,7 @@ class UnaryMaskOp:
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
"op": (["invert", "average", "round", "clamp"],),
|
||||
"op": (["invert", "average", "round", "clamp", "abs"],),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -331,6 +336,40 @@ class UnaryMaskOp:
|
||||
return (torch.round(image),)
|
||||
elif op == "clamp":
|
||||
return (torch.min(torch.max(image, torch.tensor(0.)), torch.tensor(1.)),)
|
||||
elif op == "abs":
|
||||
return (torch.abs(image),)
|
||||
|
||||
class UnaryImageOp:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
"op": (["invert", "average", "round", "clamp", "abs"],),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "op_image"
|
||||
|
||||
CATEGORY = "Masquerade Nodes"
|
||||
|
||||
def op_image(self, image, op):
|
||||
image = tensor2rgb(image)
|
||||
if op == "invert":
|
||||
return (1. - image,)
|
||||
elif op == "average":
|
||||
mean = torch.mean(torch.mean(image,dim=2),dim=1)
|
||||
return (mean.unsqueeze(1).unsqueeze(2).repeat(1, image.shape[1], image.shape[2], 1),)
|
||||
elif op == "round":
|
||||
return (torch.round(image),)
|
||||
elif op == "clamp":
|
||||
return (torch.min(torch.max(image, torch.tensor(0.)), torch.tensor(1.)),)
|
||||
elif op == "abs":
|
||||
return (torch.abs(image),)
|
||||
|
||||
|
||||
class BlurNode:
|
||||
@@ -463,6 +502,7 @@ class MixColorByMask:
|
||||
CATEGORY = "Masquerade Nodes"
|
||||
|
||||
def mix(self, image, r, g, b, mask):
|
||||
r, g, b = r / 255., g / 255., b / 255.
|
||||
image_size = image.size()
|
||||
image2 = torch.tensor([r, g, b]).to(device=image.device).unsqueeze(0).unsqueeze(0).unsqueeze(0).repeat(image_size[0], image_size[1], image_size[2], 1)
|
||||
image, image2 = tensors2common(image, image2)
|
||||
@@ -470,6 +510,9 @@ class MixColorByMask:
|
||||
return (image * (1. - mask) + image2 * mask,)
|
||||
|
||||
class CreateRectMask:
|
||||
"""
|
||||
Creates a rectangle mask. If copy_image_size is provided, the image_width and image_height parameters are ignored and the size of the given images will be used instead.
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -522,6 +565,9 @@ class CreateRectMask:
|
||||
return (mask.unsqueeze(0),)
|
||||
|
||||
class MaskToRegion:
|
||||
"""
|
||||
Given a mask, returns a rectangular region that fits the mask with the given constraints
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -634,6 +680,9 @@ class MaskToRegion:
|
||||
return (region,)
|
||||
|
||||
class CutByMask:
|
||||
"""
|
||||
Cuts the image to the bounding box of the mask. If force_resize_width or force_resize_height are provided, the image will be resized to those dimensions. The `mask_mapping_optional` input can be provided from a 'Separate Mask Components' node to cut multiple pieces out of a single image in a batch.
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -726,6 +775,9 @@ class CutByMask:
|
||||
return (result,)
|
||||
|
||||
class SeparateMaskComponents:
|
||||
"""
|
||||
Separates a mask into multiple contiguous components. Returns the individual masks created as well as a MASK_MAPPING which can be used in other nodes when dealing with batches.
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -738,6 +790,7 @@ class SeparateMaskComponents:
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE","MASK_MAPPING")
|
||||
RETURN_NAMES = ("mask", "mask_mappings")
|
||||
FUNCTION = "separate"
|
||||
|
||||
CATEGORY = "Masquerade Nodes"
|
||||
@@ -776,6 +829,9 @@ class SeparateMaskComponents:
|
||||
|
||||
|
||||
class PasteByMask:
|
||||
"""
|
||||
Pastes `image_to_paste` onto `image_base` using `mask` to determine the location. The `resize_behavior` parameter determines how the image to paste is resized to fit the mask. If `mask_mapping_optional` obtained from a 'Separate Mask Components' node is used, it will control which image gets pasted onto which base image.
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -806,9 +862,21 @@ class PasteByMask:
|
||||
# Scale the mask to be a matching size if it isn't
|
||||
B, H, W, C = image_base.shape
|
||||
MB = mask.shape[0]
|
||||
if mask_mapping_optional is None and MB < B:
|
||||
assert(B % MB == 0)
|
||||
mask = mask.repeat(B // MB, 1, 1)
|
||||
PB = image_to_paste.shape[0]
|
||||
if mask_mapping_optional is None:
|
||||
if B < PB:
|
||||
assert(PB % B == 0)
|
||||
image_base = image_base.repeat(PB // B, 1, 1, 1)
|
||||
B, H, W, C = image_base.shape
|
||||
if MB < B:
|
||||
assert(B % MB == 0)
|
||||
mask = mask.repeat(B // MB, 1, 1)
|
||||
elif B < MB:
|
||||
assert(MB % B == 0)
|
||||
image_base = image_base.repeat(MB // B, 1, 1, 1)
|
||||
if PB < B:
|
||||
assert(B % PB == 0)
|
||||
image_to_paste = image_to_paste.repeat(B // PB, 1, 1, 1)
|
||||
mask = torch.nn.functional.interpolate(mask.unsqueeze(1), size=(H, W), mode='nearest')[:,0,:,:]
|
||||
MB, MH, MW = mask.shape
|
||||
|
||||
@@ -916,6 +984,7 @@ class GetImageSize:
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("INT","INT",)
|
||||
RETURN_NAMES = ("width", "height")
|
||||
FUNCTION = "get_size"
|
||||
|
||||
CATEGORY = "Masquerade Nodes"
|
||||
@@ -955,6 +1024,9 @@ class ChangeChannelCount:
|
||||
return (tensor2rgb(image),)
|
||||
|
||||
class ConstantMask:
|
||||
"""
|
||||
Creates a mask filled with a constant value. If copy_image_size is provided, the explicit_height and explicit_width parameters are ignored and the size of the given images will be used instead.
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -993,6 +1065,9 @@ class ConstantMask:
|
||||
return (result,)
|
||||
|
||||
class PruneByMask:
|
||||
"""
|
||||
Filters out the images in a batch that don't have an associated mask with an average pixel value of at least 0.5.
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -1016,11 +1091,241 @@ class PruneByMask:
|
||||
mean = torch.mean(torch.mean(mask,dim=2),dim=1)
|
||||
return (image[mean >= 0.5],)
|
||||
|
||||
class MakeImageBatch:
|
||||
"""
|
||||
Creates a batch of images from multiple individual images or batches.
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image1": ("IMAGE",),
|
||||
},
|
||||
"optional": {
|
||||
"image2": ("IMAGE",),
|
||||
"image3": ("IMAGE",),
|
||||
"image4": ("IMAGE",),
|
||||
"image5": ("IMAGE",),
|
||||
"image6": ("IMAGE",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "append"
|
||||
|
||||
CATEGORY = "Masquerade Nodes"
|
||||
|
||||
def append(self, image1, image2 = None, image3 = None, image4 = None, image5 = None, image6 = None):
|
||||
result = image1
|
||||
if image2 is not None:
|
||||
result = torch.cat((result, image2), 0)
|
||||
if image3 is not None:
|
||||
result = torch.cat((result, image3), 0)
|
||||
if image4 is not None:
|
||||
result = torch.cat((result, image4), 0)
|
||||
if image5 is not None:
|
||||
result = torch.cat((result, image5), 0)
|
||||
if image6 is not None:
|
||||
result = torch.cat((result, image6), 0)
|
||||
return (result,)
|
||||
|
||||
class CreateQRCodeNode:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"text": ("STRING", {"multiline": True}),
|
||||
"size": ("INT", {"default": 512, "min": 64, "max": 4096, "step": 64}),
|
||||
"qr_version": ("INT", {"default": 1, "min": 1, "max": 40, "step": 1}),
|
||||
"error_correction": (["L", "M", "Q", "H"], {"default": "H"}),
|
||||
"box_size": ("INT", {"default": 10, "min": 1, "max": 100, "step": 1}),
|
||||
"border": ("INT", {"default": 4, "min": 0, "max": 100, "step": 1}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "create_qr_code"
|
||||
|
||||
CATEGORY = "Masquerade Nodes"
|
||||
|
||||
def create_qr_code(self, text, size, qr_version, error_correction, box_size, border):
|
||||
ensure_package("qrcode")
|
||||
import qrcode
|
||||
if error_correction =="L":
|
||||
error_level = qrcode.constants.ERROR_CORRECT_L
|
||||
elif error_correction =="M":
|
||||
error_level = qrcode.constants.ERROR_CORRECT_M
|
||||
elif error_correction =="Q":
|
||||
error_level = qrcode.constants.ERROR_CORRECT_Q
|
||||
else:
|
||||
error_level = qrcode.constants.ERROR_CORRECT_H
|
||||
|
||||
qr = qrcode.QRCode(
|
||||
version=qr_version,
|
||||
error_correction=error_level,
|
||||
box_size=box_size,
|
||||
border=border)
|
||||
qr.add_data(text)
|
||||
qr.make(fit=True)
|
||||
img = qr.make_image(fill_color="black", back_color="white")
|
||||
img = img.resize((size,size))
|
||||
# Convert img (a PIL Image) into a torch tensor
|
||||
tensor = torch.from_numpy(np.array(img))
|
||||
return (tensor2rgb(tensor.unsqueeze(0)),)
|
||||
|
||||
def rgb2hsv(rgb):
|
||||
# rgb is a tensor in the form [B, H, W, C]
|
||||
r = rgb[...,0]
|
||||
g = rgb[...,1]
|
||||
b = rgb[...,2]
|
||||
|
||||
hsv = torch.zeros_like(rgb)
|
||||
hsv_h = hsv[...,0]
|
||||
hsv_s = hsv[...,1]
|
||||
hsv_v = hsv[...,2]
|
||||
|
||||
# Value
|
||||
hsv_v[:], max_idx = torch.max(rgb, dim=3)
|
||||
|
||||
chroma = hsv_v - torch.min(rgb, dim=3).values
|
||||
|
||||
# Hue
|
||||
sixth = 1.0 / 6.0
|
||||
hsv_h[max_idx == 0] = (sixth * ((g - b) / chroma % 6))[max_idx == 0]
|
||||
hsv_h[max_idx == 1] = (sixth * ((b - r) / chroma + 2))[max_idx == 1]
|
||||
hsv_h[max_idx == 2] = (sixth * ((r - g) / chroma + 4))[max_idx == 2]
|
||||
hsv_h[chroma == 0] = 0
|
||||
|
||||
# Saturation
|
||||
hsv_s[chroma != 0] = chroma[chroma != 0] / hsv_v[chroma != 0]
|
||||
|
||||
return hsv
|
||||
|
||||
def hsv2rgb(hsv):
|
||||
# hsv is a tensor in the form [B, H, W, C] where C is (h,s,v)
|
||||
h = hsv[...,0]
|
||||
h = h % 1.0
|
||||
s = hsv[...,1]
|
||||
v = hsv[...,2]
|
||||
|
||||
rgb = torch.zeros_like(hsv)
|
||||
|
||||
chroma = v * s
|
||||
hp = (h * 6.0).type(torch.uint8)
|
||||
x = chroma * (1 - torch.abs((h * 6.0) % 2 - 1))
|
||||
|
||||
zeros = torch.zeros_like(x)
|
||||
rgb[hp == 0] = torch.stack([chroma, x, zeros], dim=3)[hp == 0]
|
||||
rgb[hp == 1] = torch.stack([x, chroma, zeros], dim=3)[hp == 1]
|
||||
rgb[hp == 2] = torch.stack([zeros, chroma, x], dim=3)[hp == 2]
|
||||
rgb[hp == 3] = torch.stack([zeros, x, chroma], dim=3)[hp == 3]
|
||||
rgb[hp == 4] = torch.stack([x, zeros, chroma], dim=3)[hp == 4]
|
||||
rgb[hp == 5] = torch.stack([chroma, zeros, x], dim=3)[hp == 5]
|
||||
|
||||
rgb += (v - chroma).unsqueeze(3).repeat(1,1,1,3)
|
||||
return rgb
|
||||
|
||||
def hsv2hsl(hsv):
|
||||
hsl = torch.zeros_like(hsv)
|
||||
h = hsv[...,0]
|
||||
s = hsv[...,1]
|
||||
v = hsv[...,2]
|
||||
|
||||
hsl[...,0] = h
|
||||
hsl[...,2] = v * (1. - s / 2.)
|
||||
l = hsl[...,2]
|
||||
defined = (l != 0) & (l != 1)
|
||||
hsl[...,1][defined] = ((v - l) / torch.min(l, 1. - l))[defined]
|
||||
return hsl
|
||||
|
||||
def hsl2hsv(hsl):
|
||||
hsv = torch.zeros_like(hsl)
|
||||
h = hsl[...,0]
|
||||
s = hsl[...,1]
|
||||
l = hsl[...,2]
|
||||
|
||||
hsv[...,0] = h
|
||||
hsv[...,2] = l + s * torch.min(l, 1. - l)
|
||||
v = hsv[...,2]
|
||||
defined = (v != 0)
|
||||
hsv[...,1][defined] = (2. * (1. - l / v))[defined]
|
||||
return hsv
|
||||
|
||||
class ConvertColorSpace:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"in_space": (["RGB", "HSV", "HSL"],),
|
||||
"out_space": (["RGB", "HSV", "HSL"],),
|
||||
"image": ("IMAGE",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "convert_color_space"
|
||||
|
||||
CATEGORY = "Masquerade Nodes"
|
||||
|
||||
def convert_color_space(self, in_space, out_space, image):
|
||||
if in_space == out_space:
|
||||
return (image,)
|
||||
|
||||
image = tensor2rgb(image)
|
||||
|
||||
if in_space == "HSV":
|
||||
hsv = image
|
||||
if in_space == "RGB":
|
||||
hsv = rgb2hsv(image)
|
||||
elif in_space == "HSL":
|
||||
hsv = hsl2hsv(image)
|
||||
|
||||
# We are now in RGB or HSV
|
||||
if out_space == "HSV":
|
||||
return (hsv,)
|
||||
elif out_space == "RGB":
|
||||
return (hsv2rgb(hsv),)
|
||||
else:
|
||||
assert out_space == "HSL"
|
||||
return (hsv2hsl(hsv),)
|
||||
|
||||
class MaqueradeIncrementerNode:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"seed": ("INT", {"default": 0, "min": -1, "max": 0xffffffffffffffff, "step": 1}),
|
||||
"max_value": ("INT", {"default": 1, "min": 1, "max": 0xffffffffffffffff, "step": 1}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("INT",)
|
||||
FUNCTION = "increment"
|
||||
|
||||
CATEGORY = "Masquerade Nodes"
|
||||
|
||||
def increment(self, seed, max_value):
|
||||
return (seed % max_value,)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"Mask By Text": ClipSegNode,
|
||||
"Mask Morphology": MaskMorphologyNode,
|
||||
"Combine Masks": MaskCombineOp,
|
||||
"Unary Mask Op": UnaryMaskOp,
|
||||
"Unary Image Op": UnaryImageOp,
|
||||
"Blur": BlurNode,
|
||||
"Image To Mask": ImageToMask,
|
||||
"Mix Images By Mask": MixByMask,
|
||||
@@ -1034,4 +1339,33 @@ NODE_CLASS_MAPPINGS = {
|
||||
"Prune By Mask": PruneByMask,
|
||||
"Separate Mask Components": SeparateMaskComponents,
|
||||
"Create Rect Mask": CreateRectMask,
|
||||
"Make Image Batch": MakeImageBatch,
|
||||
"Create QR Code": CreateQRCodeNode,
|
||||
"Convert Color Space": ConvertColorSpace,
|
||||
"MasqueradeIncrementer": MaqueradeIncrementerNode,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"Mask By Text": "Mask By Text",
|
||||
"Mask Morphology": "Mask Morphology",
|
||||
"Combine Masks": "Combine Masks",
|
||||
"Unary Mask Op": "Unary Mask Op",
|
||||
"Unary Image Op": "Unary Image Op",
|
||||
"Blur": "Blur",
|
||||
"Image To Mask": "Image To Mask",
|
||||
"Mix Images By Mask": "Mix Images By Mask",
|
||||
"Mix Color By Mask": "Mix Color By Mask",
|
||||
"Mask To Region": "Mask To Region",
|
||||
"Cut By Mask": "Cut By Mask",
|
||||
"Paste By Mask": "Paste By Mask",
|
||||
"Get Image Size": "Get Image Size",
|
||||
"Change Channel Count": "Change Channel Count",
|
||||
"Constant Mask": "Constant Mask",
|
||||
"Prune By Mask": "Prune By Mask",
|
||||
"Separate Mask Components": "Separate Mask Components",
|
||||
"Create Rect Mask": "Create Rect Mask",
|
||||
"Make Image Batch": "Make Image Batch",
|
||||
"Create QR Code": "Create QR Code",
|
||||
"Convert Color Space": "Convert Color Space",
|
||||
"MasqueradeIncrementer": "Incrementer",
|
||||
}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
# Recommended Alternatives
|
||||
This node pack was created as a dependency-free library before the [ComfyUI Manager](https://github.com/ltdrdata/ComfyUI-Manager) made installing dependencies easy for end-users.
|
||||
|
||||
Unless you specifically need a library without dependencies, I recommend using [Impact Pack](https://github.com/ltdrdata/ComfyUI-Impact-Pack) instead. It's a more feature-rich and well-maintained alternative for dealing with masks and segmentation.
|
||||
|
||||
# Masquerade Nodes
|
||||
|
||||
This is a node pack for ComfyUI, primarily dealing with masks. Some example workflows this pack enables are:
|
||||
@@ -80,6 +85,7 @@ The lynchpin of these workflows is the [Mask by Text](#mask-by-text) node. This
|
||||
* `average` - Sets the value of all pixels in the mask to be equal to the value of the average pixel.
|
||||
* `round` - Rounds all pixels to the nearest integer (generally 0 or 1).
|
||||
* `clamp` - Clamps all values between 0 and 1.
|
||||
* `abs` - Takes the absolute value of all pixels.
|
||||
|
||||
#### Outputs
|
||||
1. The resultant mask.
|
||||
@@ -87,6 +93,20 @@ The lynchpin of these workflows is the [Mask by Text](#mask-by-text) node. This
|
||||
#### Tips
|
||||
* Average is deceptively useful. For example, you can use two Mask to Text nodes with different concepts (like 'New York' and 'Chicago') and average the raw ClipSeg result to see which city the image is more likely to depict.
|
||||
|
||||
## Unary Image Op
|
||||
This node is the same as Unary Mask Op, but will operate across all channels of an image individually. This can be particularly useful after converting to HSV colorspace.
|
||||
#### Inputs
|
||||
* `image` - The image to operate on.
|
||||
* `op` - The operation to perform.
|
||||
* `invert` - Inverts all channels of the image.
|
||||
* `average` - Sets the value of all pixels in the image to be equal to the value of the average pixel in that channel.
|
||||
* `round` - Rounds all pixels to the nearest integer (generally 0 or 1).
|
||||
* `clamp` - Clamps all values between 0 and 1.
|
||||
* `abs` - Takes the absolute value of all pixels.
|
||||
|
||||
#### Outputs
|
||||
1. The resultant image.
|
||||
|
||||
## Blur
|
||||
#### Inputs
|
||||
* `image` - The image to blur.
|
||||
@@ -258,3 +278,24 @@ The lynchpin of these workflows is the [Mask by Text](#mask-by-text) node. This
|
||||
* `image_width` - The width of the overall image to use. Will only be used if `copy_image_size` is empty.
|
||||
* `image_height` - The height of the overall image to use. Will only be used if `copy_image_size` is empty.
|
||||
* `copy_image_size` - If specified, the mask will have the same size as the given image.
|
||||
|
||||
## Create QR Code
|
||||
#### Inputs
|
||||
* `text` - The content to embed in the QR Code
|
||||
* `size` - The size of the QR Code (across height and width) in pixels.
|
||||
* `qr_version` - The version of QR Code to use. Higher versions can encode more data, but are larger.
|
||||
* `error_correction` - The level of error correction to use.
|
||||
* `box_size` - The size of each box in the QR Code in pixels.
|
||||
* `border` - The size of the border around the QR Code in pixels.
|
||||
|
||||
## Convert Color Space
|
||||
#### Inputs
|
||||
* `image` - The image to convert.
|
||||
* `in_space` - The color space of the input image -- valid values are `RGB`, `HSV`, and `HSL`.
|
||||
* `out_space` - The color space of the output image -- valid values are `RGB`, `HSV`, and `HSL`.
|
||||
|
||||
## Incrementer
|
||||
#### Inputs
|
||||
* `seed` - The current value.
|
||||
* `control_after_generate` - Set to "Increment" to actually increment.
|
||||
* `max_value` - The value to perform modulo against
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
from .MaskNodes import NODE_CLASS_MAPPINGS
|
||||
from .MaskNodes import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
|
||||
|
||||
__all__ = ['NODE_CLASS_MAPPINGS']
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
|
||||
|
||||
Reference in New Issue
Block a user