utils update

This commit is contained in:
PozzettiAndrea
2026-03-01 14:40:30 +00:00
parent d6d3261a36
commit e848839b2f
4 changed files with 34 additions and 22 deletions
+12 -12
View File
@@ -15,55 +15,55 @@ import torch
from PIL import Image
# ── ComfyUI ↔ numpy ──────────────────────────────────────────────
# -- ComfyUI <-> numpy ---------------------------------------------------
def comfy_to_numpy(image: torch.Tensor, index: int = 0) -> np.ndarray:
"""ComfyUI IMAGE [B,H,W,C] float32 → numpy [H,W,C] uint8."""
"""ComfyUI IMAGE [B,H,W,C] float32 -> numpy [H,W,C] uint8."""
return (image[index].cpu().numpy() * 255).clip(0, 255).astype(np.uint8)
def numpy_to_comfy(image: np.ndarray) -> torch.Tensor:
"""numpy [H,W,C] uint8 → ComfyUI IMAGE [1,H,W,C] float32."""
"""numpy [H,W,C] uint8 -> ComfyUI IMAGE [1,H,W,C] float32."""
return torch.from_numpy(image.astype(np.float32) / 255.0).unsqueeze(0)
# ── ComfyUI ↔ PIL ────────────────────────────────────────────────
# -- ComfyUI <-> PIL -----------------------------------------------------
def comfy_to_pil(image: torch.Tensor, index: int = 0) -> Image.Image:
"""ComfyUI IMAGE [B,H,W,C] float32 → PIL Image (RGB)."""
"""ComfyUI IMAGE [B,H,W,C] float32 -> PIL Image (RGB)."""
return Image.fromarray(comfy_to_numpy(image, index))
def pil_to_comfy(image: Image.Image) -> torch.Tensor:
"""PIL Image → ComfyUI IMAGE [1,H,W,C] float32."""
"""PIL Image -> ComfyUI IMAGE [1,H,W,C] float32."""
return numpy_to_comfy(np.array(image.convert("RGB")))
# ── ComfyUI ↔ CHW (model input) ─────────────────────────────────
# -- ComfyUI <-> CHW (model input) ---------------------------------------
def comfy_to_chw(image: torch.Tensor) -> torch.Tensor:
"""ComfyUI IMAGE [B,H,W,C] → model input [B,C,H,W]."""
"""ComfyUI IMAGE [B,H,W,C] -> model input [B,C,H,W]."""
return image.movedim(-1, 1)
def chw_to_comfy(image: torch.Tensor) -> torch.Tensor:
"""Model output [B,C,H,W] → ComfyUI IMAGE [B,H,W,C]."""
"""Model output [B,C,H,W] -> ComfyUI IMAGE [B,H,W,C]."""
return image.movedim(1, -1)
# ── Mask conversions ─────────────────────────────────────────────
# -- Mask conversions ----------------------------------------------------
def mask_to_image(mask: torch.Tensor) -> torch.Tensor:
"""ComfyUI MASK [B,H,W] → ComfyUI IMAGE [B,H,W,3] (grayscale RGB)."""
"""ComfyUI MASK [B,H,W] -> ComfyUI IMAGE [B,H,W,3] (grayscale RGB)."""
return mask.unsqueeze(-1).expand(-1, -1, -1, 3)
def image_to_mask(image: torch.Tensor) -> torch.Tensor:
"""ComfyUI IMAGE [B,H,W,C] → ComfyUI MASK [B,H,W] (luminance)."""
"""ComfyUI IMAGE [B,H,W,C] -> ComfyUI MASK [B,H,W] (luminance)."""
if image.shape[-1] == 1:
return image.squeeze(-1)
# ITU-R BT.601 luminance
+1 -1
View File
@@ -116,7 +116,7 @@ class LoadImageWithExif(io.ComfyNode):
description="Load an image and extract focal length from EXIF metadata (35mm equivalent).",
inputs=[
io.Combo.Input("image", options=_get_image_files(),
image_upload=True),
upload=io.UploadType.image),
io.Float.Input("default_focal_mm", default=30.0, min=1.0, max=500.0, step=0.1,
optional=True,
tooltip="Default focal length (35mm equiv) if not found in EXIF"),
+20 -8
View File
@@ -33,6 +33,18 @@ _encode_cache = {
}
def _monodepth_to(output, device):
"""Move all tensors in a MonodepthOutput to the given device."""
from .sharp.model import MonodepthOutput
return MonodepthOutput(
disparity=output.disparity.to(device),
encoder_features=[t.to(device) for t in output.encoder_features],
decoder_features=output.decoder_features.to(device),
output_features=[t.to(device) for t in output.output_features],
intermediate_features=[t.to(device) for t in output.intermediate_features],
)
def _compute_image_hash(image_np: np.ndarray) -> str:
"""Compute hash of image for cache key."""
return hashlib.sha256(image_np.tobytes()).hexdigest()[:16]
@@ -242,8 +254,8 @@ def _predict_image_cached(
if _encode_cache["image_hash"] == image_hash:
# Cache hit - reuse encoded features
log.info("Cache hit - reusing encoded features (focal_length change is instant)")
monodepth_output = _encode_cache["monodepth_output"]
image_resized_pt = _encode_cache["image_resized"]
monodepth_output = _monodepth_to(_encode_cache["monodepth_output"], device)
image_resized_pt = _encode_cache["image_resized"].to(device)
else:
# Cache miss - need to encode
log.info("Encoding...")
@@ -270,15 +282,15 @@ def _predict_image_cached(
monodepth_output, _ = predictor.encode(image_resized_pt)
log.info(f"Encode time: {time.time() - encode_start:.2f}s")
# Update cache (store on CPU to free VRAM)
_encode_cache["image_hash"] = image_hash
_encode_cache["monodepth_output"] = _monodepth_to(monodepth_output, "cpu")
_encode_cache["image_resized"] = image_resized_pt.cpu()
_encode_cache["original_shape"] = (height, width)
# Release fragmented GPU memory after heavy encode (35 ViT passes)
comfy.model_management.soft_empty_cache()
# Update cache
_encode_cache["image_hash"] = image_hash
_encode_cache["monodepth_output"] = monodepth_output
_encode_cache["image_resized"] = image_resized_pt
_encode_cache["original_shape"] = (height, width)
# Decode - always run with current focal length
disparity_factor = torch.tensor([f_px / width]).float().to(device)
+1 -1
View File
@@ -13,4 +13,4 @@ pillow-heif>=0.10.0
huggingface-hub>=0.16.0
# Hugging Face transfer extension (faster downloads on Windows)
hf_xet
hf_xet