mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-05-10 09:12:31 +08:00
Merge branch 'master' into math-exp-bool
This commit is contained in:
commit
1ff7347993
@ -91,6 +91,7 @@ parser.add_argument("--directml", type=int, nargs="?", metavar="DIRECTML_DEVICE"
|
|||||||
|
|
||||||
parser.add_argument("--oneapi-device-selector", type=str, default=None, metavar="SELECTOR_STRING", help="Sets the oneAPI device(s) this instance will use.")
|
parser.add_argument("--oneapi-device-selector", type=str, default=None, metavar="SELECTOR_STRING", help="Sets the oneAPI device(s) this instance will use.")
|
||||||
parser.add_argument("--supports-fp8-compute", action="store_true", help="ComfyUI will act like if the device supports fp8 compute.")
|
parser.add_argument("--supports-fp8-compute", action="store_true", help="ComfyUI will act like if the device supports fp8 compute.")
|
||||||
|
parser.add_argument("--enable-triton-backend", action="store_true", help="ComfyUI will enable the use of Triton backend in comfy-kitchen. Is disabled at launch by default.")
|
||||||
|
|
||||||
class LatentPreviewMethod(enum.Enum):
|
class LatentPreviewMethod(enum.Enum):
|
||||||
NoPreviews = "none"
|
NoPreviews = "none"
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import torch
|
import torch
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from comfy.cli_args import args
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import comfy_kitchen as ck
|
import comfy_kitchen as ck
|
||||||
from comfy_kitchen.tensor import (
|
from comfy_kitchen.tensor import (
|
||||||
@ -21,7 +23,15 @@ try:
|
|||||||
ck.registry.disable("cuda")
|
ck.registry.disable("cuda")
|
||||||
logging.warning("WARNING: You need pytorch with cu130 or higher to use optimized CUDA operations.")
|
logging.warning("WARNING: You need pytorch with cu130 or higher to use optimized CUDA operations.")
|
||||||
|
|
||||||
ck.registry.disable("triton")
|
if args.enable_triton_backend:
|
||||||
|
try:
|
||||||
|
import triton
|
||||||
|
logging.info("Found triton %s. Enabling comfy-kitchen triton backend.", triton.__version__)
|
||||||
|
except ImportError as e:
|
||||||
|
logging.error(f"Failed to import triton, Error: {e}, the comfy-kitchen triton backend will not be available.")
|
||||||
|
ck.registry.disable("triton")
|
||||||
|
else:
|
||||||
|
ck.registry.disable("triton")
|
||||||
for k, v in ck.list_backends().items():
|
for k, v in ck.list_backends().items():
|
||||||
logging.info(f"Found comfy_kitchen backend {k}: {v}")
|
logging.info(f"Found comfy_kitchen backend {k}: {v}")
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
|
|||||||
@ -202,14 +202,11 @@ class JoinImageWithAlpha(io.ComfyNode):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def execute(cls, image: torch.Tensor, alpha: torch.Tensor) -> io.NodeOutput:
|
def execute(cls, image: torch.Tensor, alpha: torch.Tensor) -> io.NodeOutput:
|
||||||
batch_size = min(len(image), len(alpha))
|
batch_size = max(len(image), len(alpha))
|
||||||
out_images = []
|
|
||||||
|
|
||||||
alpha = 1.0 - resize_mask(alpha, image.shape[1:])
|
alpha = 1.0 - resize_mask(alpha, image.shape[1:])
|
||||||
for i in range(batch_size):
|
alpha = comfy.utils.repeat_to_batch_size(alpha, batch_size)
|
||||||
out_images.append(torch.cat((image[i][:,:,:3], alpha[i].unsqueeze(2)), dim=2))
|
image = comfy.utils.repeat_to_batch_size(image, batch_size)
|
||||||
|
return io.NodeOutput(torch.cat((image[..., :3], alpha.unsqueeze(-1)), dim=-1))
|
||||||
return io.NodeOutput(torch.stack(out_images))
|
|
||||||
|
|
||||||
|
|
||||||
class CompositingExtension(ComfyExtension):
|
class CompositingExtension(ComfyExtension):
|
||||||
|
|||||||
@ -666,12 +666,13 @@ class ColorTransfer(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="ColorTransfer",
|
node_id="ColorTransfer",
|
||||||
|
display_name="Color Transfer",
|
||||||
category="image/postprocessing",
|
category="image/postprocessing",
|
||||||
description="Match the colors of one image to another using various algorithms.",
|
description="Match the colors of one image to another using various algorithms.",
|
||||||
search_aliases=["color match", "color grading", "color correction", "match colors", "color transform", "mkl", "reinhard", "histogram"],
|
search_aliases=["color match", "color grading", "color correction", "match colors", "color transform", "mkl", "reinhard", "histogram"],
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Image.Input("image_target", tooltip="Image(s) to apply the color transform to."),
|
io.Image.Input("image_target", tooltip="Image(s) to apply the color transform to."),
|
||||||
io.Image.Input("image_ref", optional=True, tooltip="Reference image(s) to match colors to. If not provided, processing is skipped"),
|
io.Image.Input("image_ref", tooltip="Reference image(s) to match colors to."),
|
||||||
io.Combo.Input("method", options=['reinhard_lab', 'mkl_lab', 'histogram'],),
|
io.Combo.Input("method", options=['reinhard_lab', 'mkl_lab', 'histogram'],),
|
||||||
io.DynamicCombo.Input("source_stats",
|
io.DynamicCombo.Input("source_stats",
|
||||||
tooltip="per_frame: each frame matched to image_ref individually. uniform: pool stats across all source frames as baseline, match to image_ref. target_frame: use one chosen frame as the baseline for the transform to image_ref, applied uniformly to all frames (preserves relative differences)",
|
tooltip="per_frame: each frame matched to image_ref individually. uniform: pool stats across all source frames as baseline, match to image_ref. target_frame: use one chosen frame as the baseline for the transform to image_ref, applied uniformly to all frames (preserves relative differences)",
|
||||||
|
|||||||
@ -49,7 +49,7 @@ class Int(io.ComfyNode):
|
|||||||
display_name="Int",
|
display_name="Int",
|
||||||
category="utils/primitive",
|
category="utils/primitive",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Int.Input("value", min=-sys.maxsize, max=sys.maxsize, control_after_generate=True),
|
io.Int.Input("value", min=-sys.maxsize, max=sys.maxsize, control_after_generate=io.ControlAfterGenerate.fixed),
|
||||||
],
|
],
|
||||||
outputs=[io.Int.Output()],
|
outputs=[io.Int.Output()],
|
||||||
)
|
)
|
||||||
|
|||||||
66
nodes.py
66
nodes.py
@ -1754,57 +1754,49 @@ class LoadImage:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
class LoadImageMask:
|
|
||||||
|
class LoadImageMask(LoadImage):
|
||||||
ESSENTIALS_CATEGORY = "Image Tools"
|
ESSENTIALS_CATEGORY = "Image Tools"
|
||||||
SEARCH_ALIASES = ["import mask", "alpha mask", "channel mask"]
|
SEARCH_ALIASES = ["import mask", "alpha mask", "channel mask"]
|
||||||
|
|
||||||
_color_channels = ["alpha", "red", "green", "blue"]
|
_color_channels = ["alpha", "red", "green", "blue"]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
input_dir = folder_paths.get_input_directory()
|
types = super().INPUT_TYPES()
|
||||||
files = [f for f in os.listdir(input_dir) if os.path.isfile(os.path.join(input_dir, f))]
|
return {
|
||||||
return {"required":
|
"required": {
|
||||||
{"image": (sorted(files), {"image_upload": True}),
|
**types["required"],
|
||||||
"channel": (s._color_channels, ), }
|
"channel": (s._color_channels, )
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CATEGORY = "mask"
|
CATEGORY = "mask"
|
||||||
|
|
||||||
RETURN_TYPES = ("MASK",)
|
RETURN_TYPES = ("MASK",)
|
||||||
FUNCTION = "load_image"
|
FUNCTION = "load_image_mask"
|
||||||
def load_image(self, image, channel):
|
|
||||||
image_path = folder_paths.get_annotated_filepath(image)
|
def load_image_mask(self, image, channel):
|
||||||
i = node_helpers.pillow(Image.open, image_path)
|
image_tensor, mask_tensor = super().load_image(image)
|
||||||
i = node_helpers.pillow(ImageOps.exif_transpose, i)
|
|
||||||
if i.getbands() != ("R", "G", "B", "A"):
|
|
||||||
if i.mode == 'I':
|
|
||||||
i = i.point(lambda i: i * (1 / 255))
|
|
||||||
i = i.convert("RGBA")
|
|
||||||
mask = None
|
|
||||||
c = channel[0].upper()
|
c = channel[0].upper()
|
||||||
if c in i.getbands():
|
|
||||||
mask = np.array(i.getchannel(c)).astype(np.float32) / 255.0
|
if c == 'A':
|
||||||
mask = torch.from_numpy(mask)
|
return (mask_tensor,)
|
||||||
if c == 'A':
|
|
||||||
mask = 1. - mask
|
channel_idx = {'R': 0, 'G': 1, 'B': 2}.get(c, 0)
|
||||||
|
|
||||||
|
if channel_idx < image_tensor.shape[-1]:
|
||||||
|
return (image_tensor[..., channel_idx].clone(),)
|
||||||
else:
|
else:
|
||||||
mask = torch.zeros((64,64), dtype=torch.float32, device="cpu")
|
empty_mask = torch.zeros(
|
||||||
return (mask.unsqueeze(0),)
|
image_tensor.shape[:-1],
|
||||||
|
dtype=image_tensor.dtype,
|
||||||
|
device=image_tensor.device
|
||||||
|
)
|
||||||
|
return (empty_mask,)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def IS_CHANGED(s, image, channel):
|
def IS_CHANGED(s, image, channel):
|
||||||
image_path = folder_paths.get_annotated_filepath(image)
|
return super().IS_CHANGED(image)
|
||||||
m = hashlib.sha256()
|
|
||||||
with open(image_path, 'rb') as f:
|
|
||||||
m.update(f.read())
|
|
||||||
return m.digest().hex()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def VALIDATE_INPUTS(s, image):
|
|
||||||
if not folder_paths.exists_annotated_filepath(image):
|
|
||||||
return "Invalid image file: {}".format(image)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class LoadImageOutput(LoadImage):
|
class LoadImageOutput(LoadImage):
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import errno
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import asyncio
|
import asyncio
|
||||||
@ -1245,7 +1246,13 @@ class PromptServer():
|
|||||||
address = addr[0]
|
address = addr[0]
|
||||||
port = addr[1]
|
port = addr[1]
|
||||||
site = web.TCPSite(runner, address, port, ssl_context=ssl_ctx)
|
site = web.TCPSite(runner, address, port, ssl_context=ssl_ctx)
|
||||||
await site.start()
|
try:
|
||||||
|
await site.start()
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno == errno.EADDRINUSE:
|
||||||
|
logging.error(f"Port {port} is already in use on address {address}. Please close the other application or use a different port with --port.")
|
||||||
|
raise SystemExit(1)
|
||||||
|
raise
|
||||||
|
|
||||||
if not hasattr(self, 'address'):
|
if not hasattr(self, 'address'):
|
||||||
self.address = address #TODO: remove this
|
self.address = address #TODO: remove this
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user