Spaces:
Sleeping
Sleeping
| import torch | |
| import torch.nn.functional as F | |
| import numpy as np | |
| from PIL import Image | |
| import comfy.model_management | |
| from comfy.comfy_types import IO, ComfyNodeABC, InputTypeDict | |
| from comfy_api.latest import io | |
| class IntensityDepthEstimation(ComfyNodeABC): | |
| """ | |
| Simple intensity-based depth estimation node. | |
| Converts grayscale intensity to depth values using various methods. | |
| """ | |
| def INPUT_TYPES(cls) -> InputTypeDict: | |
| return { | |
| "required": { | |
| "image": (IO.IMAGE, {"tooltip": "Input image for depth estimation"}), | |
| "method": (["intensity", "inverted_intensity", "gradient", "sobel"], { | |
| "default": "intensity", | |
| "tooltip": "Depth estimation method" | |
| }), | |
| "depth_range": (IO.FLOAT, { | |
| "default": 1.0, | |
| "min": 0.1, | |
| "max": 10.0, | |
| "step": 0.1, | |
| "tooltip": "Maximum depth range" | |
| }), | |
| "normalize": (IO.BOOLEAN, { | |
| "default": True, | |
| "tooltip": "Normalize depth values to 0-1 range" | |
| }), | |
| }, | |
| "optional": { | |
| "blur_radius": (IO.FLOAT, { | |
| "default": 1.0, | |
| "min": 0.0, | |
| "max": 10.0, | |
| "step": 0.1, | |
| "tooltip": "Gaussian blur radius for smoothing" | |
| }), | |
| } | |
| } | |
| RETURN_TYPES = (IO.IMAGE,) | |
| RETURN_NAMES = ("depth_image",) | |
| FUNCTION = "estimate_depth" | |
| CATEGORY = "image/processing" | |
| DESCRIPTION = "Simple intensity-based depth estimation using various methods" | |
| def estimate_depth(self, image, method, depth_range, normalize, blur_radius=1.0): | |
| """ | |
| Estimate depth from image intensity using various methods. | |
| Args: | |
| image: Input image tensor [B, H, W, C] | |
| method: Depth estimation method | |
| depth_range: Maximum depth range | |
| normalize: Whether to normalize output | |
| blur_radius: Gaussian blur radius for smoothing | |
| Returns: | |
| depth_image: Estimated depth map [B, H, W, C] | |
| """ | |
| device = comfy.model_management.get_torch_device() | |
| image = image.to(device) | |
| # Convert to grayscale if needed | |
| if image.shape[-1] > 1: | |
| # Convert RGB to grayscale using standard weights | |
| gray = 0.299 * image[..., 0:1] + 0.587 * image[..., 1:2] + 0.114 * image[..., 2:3] | |
| else: | |
| gray = image | |
| # Apply Gaussian blur if specified | |
| if blur_radius > 0: | |
| gray = self._apply_gaussian_blur(gray, blur_radius) | |
| # Apply depth estimation method | |
| if method == "intensity": | |
| depth = gray | |
| elif method == "inverted_intensity": | |
| depth = 1.0 - gray | |
| elif method == "gradient": | |
| depth = self._compute_gradient_depth(gray) | |
| elif method == "sobel": | |
| depth = self._compute_sobel_depth(gray) | |
| else: | |
| depth = gray | |
| # Scale by depth range | |
| depth = depth * depth_range | |
| # Normalize if requested | |
| if normalize: | |
| depth_min = depth.min() | |
| depth_max = depth.max() | |
| if depth_max > depth_min: | |
| depth = (depth - depth_min) / (depth_max - depth_min) | |
| else: | |
| depth = torch.zeros_like(depth) | |
| # Convert back to RGB for visualization | |
| depth_rgb = depth.repeat(1, 1, 1, 3) | |
| # Move to intermediate device | |
| depth_rgb = depth_rgb.to(comfy.model_management.intermediate_device()) | |
| return (depth_rgb,) | |
| def _apply_gaussian_blur(self, image, radius): | |
| """Apply Gaussian blur to the image.""" | |
| if radius <= 0: | |
| return image | |
| # Create Gaussian kernel | |
| kernel_size = int(2 * radius + 1) | |
| if kernel_size % 2 == 0: | |
| kernel_size += 1 | |
| # Generate Gaussian kernel | |
| sigma = radius / 3.0 | |
| x = torch.arange(kernel_size, dtype=torch.float32, device=image.device) | |
| x = x - kernel_size // 2 | |
| kernel_1d = torch.exp(-(x ** 2) / (2 * sigma ** 2)) | |
| kernel_1d = kernel_1d / kernel_1d.sum() | |
| # Create 2D kernel | |
| kernel_2d = kernel_1d[:, None] * kernel_1d[None, :] | |
| kernel_2d = kernel_2d / kernel_2d.sum() | |
| # Reshape for convolution | |
| kernel_2d = kernel_2d.view(1, 1, kernel_size, kernel_size) | |
| # Apply convolution | |
| batch_size, height, width, channels = image.shape | |
| image_reshaped = image.permute(0, 3, 1, 2) # [B, C, H, W] | |
| # Pad image | |
| pad_size = kernel_size // 2 | |
| padded = F.pad(image_reshaped, (pad_size, pad_size, pad_size, pad_size), mode='reflect') | |
| # Apply convolution | |
| blurred = F.conv2d(padded, kernel_2d, padding=0) | |
| # Reshape back | |
| blurred = blurred.permute(0, 2, 3, 1) # [B, H, W, C] | |
| return blurred | |
| def _compute_gradient_depth(self, image): | |
| """Compute depth using gradient magnitude.""" | |
| # Compute gradients | |
| grad_x = torch.diff(image, dim=2, prepend=image[:, :, :1, :]) | |
| grad_y = torch.diff(image, dim=1, prepend=image[:, :1, :, :]) | |
| # Compute gradient magnitude | |
| grad_mag = torch.sqrt(grad_x ** 2 + grad_y ** 2) | |
| # Invert so edges have higher depth | |
| depth = 1.0 - grad_mag | |
| return depth | |
| def _compute_sobel_depth(self, image): | |
| """Compute depth using Sobel edge detection.""" | |
| # Sobel kernels | |
| sobel_x = torch.tensor([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtype=torch.float32, device=image.device) | |
| sobel_y = torch.tensor([[-1, -2, -1], [0, 0, 0], [1, 2, 1]], dtype=torch.float32, device=image.device) | |
| # Reshape kernels for convolution | |
| sobel_x = sobel_x.view(1, 1, 3, 3) | |
| sobel_y = sobel_y.view(1, 1, 3, 3) | |
| # Reshape image for convolution | |
| batch_size, height, width, channels = image.shape | |
| image_reshaped = image.permute(0, 3, 1, 2) # [B, C, H, W] | |
| # Pad image | |
| padded = F.pad(image_reshaped, (1, 1, 1, 1), mode='reflect') | |
| # Apply Sobel filters | |
| grad_x = F.conv2d(padded, sobel_x, padding=0) | |
| grad_y = F.conv2d(padded, sobel_y, padding=0) | |
| # Compute gradient magnitude | |
| grad_mag = torch.sqrt(grad_x ** 2 + grad_y ** 2) | |
| # Reshape back | |
| grad_mag = grad_mag.permute(0, 2, 3, 1) # [B, H, W, C] | |
| # Invert so edges have higher depth | |
| depth = 1.0 - grad_mag | |
| return depth | |
| # Node class mappings | |
| NODE_CLASS_MAPPINGS = { | |
| "IntensityDepthEstimation": IntensityDepthEstimation, | |
| } | |
| NODE_DISPLAY_NAME_MAPPINGS = { | |
| "IntensityDepthEstimation": "Intensity Depth Estimation", | |
| } | |