Spaces:
Sleeping
Sleeping
| import torch | |
| import numpy as np | |
| import cv2 | |
| import comfy.model_management | |
| from comfy.comfy_types import IO, ComfyNodeABC, InputTypeDict | |
| from comfy_api.latest import io | |
| class CannyOpenCV(ComfyNodeABC): | |
| """ | |
| Canny edge detection using OpenCV (CPU-based). | |
| More efficient for CPU processing and provides consistent results. | |
| """ | |
| def INPUT_TYPES(cls) -> InputTypeDict: | |
| return { | |
| "required": { | |
| "image": (IO.IMAGE, { | |
| "tooltip": "Input image for edge detection" | |
| }), | |
| "low_threshold": (IO.FLOAT, { | |
| "default": 50.0, | |
| "min": 1.0, | |
| "max": 255.0, | |
| "step": 1.0, | |
| "tooltip": "Lower threshold for edge detection" | |
| }), | |
| "high_threshold": (IO.FLOAT, { | |
| "default": 150.0, | |
| "min": 1.0, | |
| "max": 255.0, | |
| "step": 1.0, | |
| "tooltip": "Upper threshold for edge detection" | |
| }), | |
| }, | |
| "optional": { | |
| "blur_kernel_size": (IO.INT, { | |
| "default": 5, | |
| "min": 1, | |
| "max": 15, | |
| "step": 2, | |
| "tooltip": "Gaussian blur kernel size (must be odd)" | |
| }), | |
| "l2_gradient": (IO.BOOLEAN, { | |
| "default": False, | |
| "tooltip": "Use L2 gradient for more accurate edge detection" | |
| }), | |
| } | |
| } | |
| RETURN_TYPES = (IO.IMAGE,) | |
| RETURN_NAMES = ("canny_image",) | |
| FUNCTION = "detect_edges" | |
| CATEGORY = "image/preprocessors" | |
| DESCRIPTION = "Canny edge detection using OpenCV (CPU-based)" | |
| def detect_edges(self, image, low_threshold, high_threshold, blur_kernel_size=5, l2_gradient=False): | |
| """ | |
| Detect edges using OpenCV Canny edge detection. | |
| Args: | |
| image: Input image tensor [B, H, W, C] | |
| low_threshold: Lower threshold for edge detection | |
| high_threshold: Upper threshold for edge detection | |
| blur_kernel_size: Gaussian blur kernel size | |
| l2_gradient: Whether to use L2 gradient | |
| Returns: | |
| canny_image: Edge-detected image tensor [B, H, W, C] | |
| """ | |
| try: | |
| # Convert to CPU for OpenCV processing | |
| image_cpu = image.cpu() | |
| # Process each image in the batch | |
| results = [] | |
| for i in range(image_cpu.shape[0]): | |
| # Get single image [H, W, C] | |
| single_image = image_cpu[i].numpy() | |
| # Convert to uint8 if needed | |
| if single_image.dtype != np.uint8: | |
| single_image = (single_image * 255).astype(np.uint8) | |
| # Convert to grayscale if needed | |
| if len(single_image.shape) == 3 and single_image.shape[2] > 1: | |
| gray = cv2.cvtColor(single_image, cv2.COLOR_RGB2GRAY) | |
| else: | |
| gray = single_image | |
| # Apply Gaussian blur | |
| if blur_kernel_size > 1: | |
| # Ensure kernel size is odd | |
| kernel_size = blur_kernel_size if blur_kernel_size % 2 == 1 else blur_kernel_size + 1 | |
| gray = cv2.GaussianBlur(gray, (kernel_size, kernel_size), 0) | |
| # Apply Canny edge detection | |
| edges = cv2.Canny( | |
| gray, | |
| int(low_threshold), | |
| int(high_threshold), | |
| L2gradient=l2_gradient | |
| ) | |
| # Convert back to RGB for consistency | |
| edges_rgb = cv2.cvtColor(edges, cv2.COLOR_GRAY2RGB) | |
| # Convert back to float32 and normalize | |
| edges_normalized = edges_rgb.astype(np.float32) / 255.0 | |
| results.append(edges_normalized) | |
| # Stack results back into batch tensor | |
| result_tensor = torch.from_numpy(np.stack(results)) | |
| # Move to appropriate device | |
| device = comfy.model_management.get_torch_device() | |
| result_tensor = result_tensor.to(device) | |
| return (result_tensor,) | |
| except Exception as e: | |
| raise RuntimeError(f"Error in Canny edge detection: {str(e)}") | |
| # Node class mappings | |
| NODE_CLASS_MAPPINGS = { | |
| "CannyOpenCV": CannyOpenCV, | |
| } | |
| NODE_DISPLAY_NAME_MAPPINGS = { | |
| "CannyOpenCV": "Canny Edge Detection (OpenCV)", | |
| } | |