From 55a8b8d2678397de4570f8be060ca0af3490c477 Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Sat, 26 Apr 2025 10:27:53 -0400 Subject: [PATCH 01/13] always equal proxy --- src/utils/general.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/utils/general.py diff --git a/src/utils/general.py b/src/utils/general.py new file mode 100644 index 0000000..e911761 --- /dev/null +++ b/src/utils/general.py @@ -0,0 +1,13 @@ +""" +General utilities for ComfyUI RealTimeNodes. +""" + +class AlwaysEqualProxy(str): + """Helper class to allow connecting multiple specific input types to a single input node. + Originally borrowed from https://github.com/theUpsider/ComfyUI-Logic + """ + def __eq__(self, _): + return True + + def __ne__(self, _): + return False \ No newline at end of file From b61a71bc6a42d91a1985945eb0adf824e407c51c Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Sat, 26 Apr 2025 10:28:33 -0400 Subject: [PATCH 02/13] iamge utils --- src/utils/image.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/utils/image.py diff --git a/src/utils/image.py b/src/utils/image.py new file mode 100644 index 0000000..5caa2fb --- /dev/null +++ b/src/utils/image.py @@ -0,0 +1,68 @@ +""" +Image processing utilities for ComfyUI RealTimeNodes. + +Contains functions for converting between different image formats, +particularly between ComfyUI tensor format (BHWC) and OpenCV format. +""" + +import torch +import numpy as np +import cv2 +from typing import List, Union, Tuple + +def convert_to_cv2(tensor: torch.Tensor) -> list: + """Converts a ComfyUI IMAGE tensor (BHWC, float32, 0-1) to a list of cv2 images (BGR, uint8).""" + if tensor.ndim != 4 or tensor.shape[3] != 3: + raise ValueError(f"Input tensor must be BHWC with 3 channels, got shape: {tensor.shape}") + + # Convert entire batch to numpy, scale to 0-255, and convert to uint8 + images_np = tensor.cpu().numpy() + images_np = (images_np * 255).clip(0, 255).astype(np.uint8) + + # Convert RGB to BGR for cv2 + cv2_images = [cv2.cvtColor(img, cv2.COLOR_RGB2BGR) for img in images_np] + return cv2_images + +def convert_to_tensor(cv2_images) -> torch.Tensor: + """Converts cv2 image(s) (BGR, uint8) to a ComfyUI IMAGE tensor (BHWC, float32, 0-1). + + Args: + cv2_images: A single cv2 image or a list of cv2 images + """ + # Handle both single image and list of images + if not isinstance(cv2_images, list): + cv2_images = [cv2_images] + + # Process each image + np_images = [] + for cv2_image in cv2_images: + # Convert BGR to RGB + rgb_image = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB) + + # Scale to 0-1 + image_np = rgb_image.astype(np.float32) / 255.0 + np_images.append(image_np) + + # Stack all images into a batch + batch_np = np.stack(np_images, axis=0) + + # Convert to tensor (already has batch dimension) + tensor = torch.from_numpy(batch_np) + + return tensor + +def create_mask_from_points(height: int, width: int, points: List[Tuple[int, int]], device='cpu') -> torch.Tensor: + """Creates a binary mask tensor from a list of points using convex hull.""" + mask = np.zeros((height, width), dtype=np.uint8) + if len(points) < 3: + return torch.from_numpy(mask).float().unsqueeze(0).to(device) + + try: + np_points = np.array(points, dtype=np.int32) + hull = cv2.convexHull(np_points) + cv2.fillPoly(mask, [hull], 1) + except Exception as e: + return torch.from_numpy(mask).float().unsqueeze(0).to(device) + + mask_tensor = torch.from_numpy(mask).float().unsqueeze(0).to(device) + return mask_tensor \ No newline at end of file From afa02c7fb1149e372b0cdc49f3e6e90956737b67 Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Sat, 26 Apr 2025 10:28:40 -0400 Subject: [PATCH 03/13] math utils --- src/utils/math.py | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/utils/math.py diff --git a/src/utils/math.py b/src/utils/math.py new file mode 100644 index 0000000..4f985d9 --- /dev/null +++ b/src/utils/math.py @@ -0,0 +1,80 @@ +""" +Math utility functions for RealTimeNodes. + +Contains functions for mathematical operations including: +- Value scaling and normalization +- Distance calculations +- Other general math operations +""" + +import math +from typing import Optional, Tuple, Any + +def scale_value(value: Optional[float], + input_min: float, input_max: float, + output_min: float, output_max: float, + clamp: bool = True) -> Optional[float]: + """ + Linearly scales a value from one range to another. + + Args: + value: The value to scale + input_min: Minimum value of input range + input_max: Maximum value of input range + output_min: Minimum value of output range + output_max: Maximum value of output range + clamp: Whether to clamp the output to the output range + + Returns: + Scaled value, or None if input was None + """ + if value is None: + return None + if input_max == input_min: # Avoid division by zero + return output_min if value <= input_min else output_max + + # Scale + scaled = output_min + (value - input_min) * (output_max - output_min) / (input_max - input_min) + + # Clamp + if clamp: + scaled = max(output_min, min(output_max, scaled)) + + return scaled + +def calculate_euclidean_distance(point1: Tuple[float, float, float], + point2: Tuple[float, float, float]) -> float: + """ + Calculates the Euclidean distance between two 3D points. + + Args: + point1: First point as (x, y, z) + point2: Second point as (x, y, z) + + Returns: + Euclidean distance between the points + """ + delta_x = point1[0] - point2[0] + delta_y = point1[1] - point2[1] + delta_z = point1[2] - point2[2] + + distance = math.sqrt(delta_x**2 + delta_y**2 + delta_z**2) + return distance + +def calculate_euclidean_distance_2d(point1: Tuple[float, float], + point2: Tuple[float, float]) -> float: + """ + Calculates the Euclidean distance between two 2D points. + + Args: + point1: First point as (x, y) + point2: Second point as (x, y) + + Returns: + Euclidean distance between the points + """ + delta_x = point1[0] - point2[0] + delta_y = point1[1] - point2[1] + + distance = math.sqrt(delta_x**2 + delta_y**2) + return distance \ No newline at end of file From d56804217d2eb9d191da705f1a5f1c979ecfebd8 Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Sat, 26 Apr 2025 10:28:50 -0400 Subject: [PATCH 04/13] timestamp proviider --- src/utils/timing.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/utils/timing.py diff --git a/src/utils/timing.py b/src/utils/timing.py new file mode 100644 index 0000000..3c6bcf9 --- /dev/null +++ b/src/utils/timing.py @@ -0,0 +1,24 @@ +""" +Timing and timestamp utilities for RealTimeNodes. +""" + +import time + +class TimestampProvider: + """ + Provides real-time, monotonic timestamps in milliseconds. + + This ensures timestamps are always increasing while staying aligned with real elapsed time. + Useful for any process that requires monotonically increasing time values. + """ + def __init__(self): + self._start_time = time.time() + self._last_timestamp = 0 + + def next(self) -> int: + """Get the next timestamp in milliseconds, guaranteed to be greater than the previous one.""" + now = int((time.time() - self._start_time) * 1000) + if now <= self._last_timestamp: + now = self._last_timestamp + 1 + self._last_timestamp = now + return now \ No newline at end of file From f7b286463cfe36be20384473a75192a55054f3ef Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Sat, 26 Apr 2025 10:29:12 -0400 Subject: [PATCH 05/13] backward compatability --- src/utils/__init__.py | 21 ++++++++++++++++++++- src/utils/general_utils.py | 9 +++------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/utils/__init__.py b/src/utils/__init__.py index da22290..ed501ed 100644 --- a/src/utils/__init__.py +++ b/src/utils/__init__.py @@ -1 +1,20 @@ -# This file intentionally left blank \ No newline at end of file +""" +Unified utilities package for ComfyUI RealTimeNodes. +""" + +# General utilities +from .general import AlwaysEqualProxy + +# Image utilities +from .image import convert_to_cv2, convert_to_tensor, create_mask_from_points + +# Math utilities +from .math import scale_value, calculate_euclidean_distance, calculate_euclidean_distance_2d + +# Timing utilities +from .timing import TimestampProvider + +# For backward compatibility, expose the original names +# This allows existing code to continue working while we transition +image_to_cv2 = convert_to_cv2 +cv2_to_image = convert_to_tensor \ No newline at end of file diff --git a/src/utils/general_utils.py b/src/utils/general_utils.py index 44b9be7..de31bed 100644 --- a/src/utils/general_utils.py +++ b/src/utils/general_utils.py @@ -1,7 +1,4 @@ -class AlwaysEqualProxy(str): - #borrowed from https://github.com/theUpsider/ComfyUI-Logic - def __eq__(self, _): - return True +from .general import AlwaysEqualProxy - def __ne__(self, _): - return False \ No newline at end of file +# This file is maintained for backward compatibility +# New code should import directly from src.utils.general \ No newline at end of file From 705d89242ba5a32677ad1a46175edf4e88e1f851 Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Sat, 26 Apr 2025 10:29:56 -0400 Subject: [PATCH 06/13] backward compat --- src/mediapipe_vision/utils/__init__.py | 10 ++++++-- src/mediapipe_vision/utils/comfy_utils.py | 12 ++++------ src/mediapipe_vision/utils/delta_utils.py | 20 ++-------------- src/mediapipe_vision/utils/image_utils.py | 8 +++++++ src/mediapipe_vision/utils/mask_utils.py | 19 ++------------- .../utils/timestamp_provider.py | 23 +++---------------- 6 files changed, 27 insertions(+), 65 deletions(-) diff --git a/src/mediapipe_vision/utils/__init__.py b/src/mediapipe_vision/utils/__init__.py index 5c7b5fd..413dd9a 100644 --- a/src/mediapipe_vision/utils/__init__.py +++ b/src/mediapipe_vision/utils/__init__.py @@ -1,8 +1,14 @@ """Utility functions for MediaPipe Vision.""" from .download_utils import download_model -from .image_utils import convert_to_cv2, convert_to_tensor -from .delta_utils import calculate_euclidean_delta, scale_value +from ...utils.image import convert_to_cv2, convert_to_tensor +from ...utils.math import scale_value + +# For backward compatibility with existing code +from .delta_utils import calculate_euclidean_delta + +# Maintain backward compatibility with existing imports +# New code should import directly from src.utils __all__ = [ "convert_to_cv2", diff --git a/src/mediapipe_vision/utils/comfy_utils.py b/src/mediapipe_vision/utils/comfy_utils.py index b1c1f39..7c77950 100644 --- a/src/mediapipe_vision/utils/comfy_utils.py +++ b/src/mediapipe_vision/utils/comfy_utils.py @@ -1,11 +1,7 @@ """Utilities specific to ComfyUI integration.""" -class AlwaysEqualProxy(str): - """Helper class to allow connecting multiple specific input types to a single input node. - Borrowed from https://github.com/theUpsider/ComfyUI-Logic - """ - def __eq__(self, _): - return True +# Import from the new consolidated utilities +from ...utils.general import AlwaysEqualProxy - def __ne__(self, _): - return False \ No newline at end of file +# This file is maintained for backward compatibility +# New code should import directly from src.utils \ No newline at end of file diff --git a/src/mediapipe_vision/utils/delta_utils.py b/src/mediapipe_vision/utils/delta_utils.py index efbbf47..b7c0ea2 100644 --- a/src/mediapipe_vision/utils/delta_utils.py +++ b/src/mediapipe_vision/utils/delta_utils.py @@ -1,6 +1,7 @@ import math from typing import Optional +from ...utils.math import scale_value from ..types import LandmarkPoint # Assuming LandmarkPoint is in src/types.py def calculate_euclidean_delta(p1: Optional[LandmarkPoint], p2: Optional[LandmarkPoint]) -> Optional[float]: @@ -15,21 +16,4 @@ def calculate_euclidean_delta(p1: Optional[LandmarkPoint], p2: Optional[Landmark distance = math.sqrt(delta_x**2 + delta_y**2 + delta_z**2) return distance -def scale_value(value: Optional[float], - delta_min: float, delta_max: float, - output_min: float, output_max: float, - clamp: bool = True) -> Optional[float]: - """Linearly scales a value from one range to another.""" - if value is None: - return None - if delta_max == delta_min: # Avoid division by zero - return output_min if value <= delta_min else output_max - - # Scale - scaled = output_min + (value - delta_min) * (output_max - output_min) / (delta_max - delta_min) - - # Clamp - if clamp: - scaled = max(output_min, min(output_max, scaled)) - - return scaled \ No newline at end of file +# scale_value is now imported from utils.math \ No newline at end of file diff --git a/src/mediapipe_vision/utils/image_utils.py b/src/mediapipe_vision/utils/image_utils.py index 9def0b3..e1a825b 100644 --- a/src/mediapipe_vision/utils/image_utils.py +++ b/src/mediapipe_vision/utils/image_utils.py @@ -1,3 +1,11 @@ +"""Image utilities for MediaPipe Vision integration.""" + +# Import from the new consolidated utilities +from ...utils.image import convert_to_cv2, convert_to_tensor + +# This file is maintained for backward compatibility +# New code should import directly from src.utils + import torch import numpy as np import cv2 diff --git a/src/mediapipe_vision/utils/mask_utils.py b/src/mediapipe_vision/utils/mask_utils.py index 3a80c74..c62b46c 100644 --- a/src/mediapipe_vision/utils/mask_utils.py +++ b/src/mediapipe_vision/utils/mask_utils.py @@ -4,23 +4,8 @@ import numpy as np import cv2 from typing import List, Tuple import logging +from ...utils.image import create_mask_from_points logger = logging.getLogger(__name__) -def create_mask_from_points(height: int, width: int, points: List[Tuple[int, int]], device='cpu') -> torch.Tensor: - """Creates a binary mask tensor from a list of points using convex hull.""" - mask = np.zeros((height, width), dtype=np.uint8) - if len(points) < 3: - logger.warning(f"Cannot create mask from {len(points)} points (need >= 3 for convex hull). Returning empty mask.") - return torch.from_numpy(mask).float().unsqueeze(0).to(device) - - try: - np_points = np.array(points, dtype=np.int32) - hull = cv2.convexHull(np_points) - cv2.fillPoly(mask, [hull], 1) - except Exception as e: - logger.error(f"Error creating mask polygon: {e}") - return torch.from_numpy(mask).float().unsqueeze(0).to(device) - - mask_tensor = torch.from_numpy(mask).float().unsqueeze(0).to(device) - return mask_tensor \ No newline at end of file +# create_mask_from_points is now imported from utils.image \ No newline at end of file diff --git a/src/mediapipe_vision/utils/timestamp_provider.py b/src/mediapipe_vision/utils/timestamp_provider.py index 871c1bb..9d8e51d 100644 --- a/src/mediapipe_vision/utils/timestamp_provider.py +++ b/src/mediapipe_vision/utils/timestamp_provider.py @@ -1,21 +1,4 @@ -import time +from ...utils.timing import TimestampProvider -class TimestampProvider: - """ - Provides real-time, monotonic timestamps in milliseconds. - - MediaPipe's RunningMode.VIDEO requires strictly increasing timestamp_ms values. - Using time.time() alone can result in duplicates during tight loops, which causes - MediaPipe to skip or freeze frames. This class ensures timestamps are always - increasing while staying aligned with real elapsed time. - """ - def __init__(self): - self._start_time = time.time() - self._last_timestamp = 0 - - def next(self) -> int: - now = int((time.time() - self._start_time) * 1000) - if now <= self._last_timestamp: - now = self._last_timestamp + 1 - self._last_timestamp = now - return now \ No newline at end of file +# This file is maintained for backward compatibility +# New code should import directly from src.utils.timing \ No newline at end of file From a731d05672dd058310f963ea9b50b66d647712ec Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Sat, 26 Apr 2025 10:51:53 -0400 Subject: [PATCH 07/13] remove shims --- src/mediapipe_vision/utils/comfy_utils.py | 7 --- src/mediapipe_vision/utils/image_utils.py | 52 ------------------- src/mediapipe_vision/utils/mask_utils.py | 11 ---- .../utils/timestamp_provider.py | 4 -- src/utils/general_utils.py | 4 -- 5 files changed, 78 deletions(-) delete mode 100644 src/mediapipe_vision/utils/comfy_utils.py delete mode 100644 src/mediapipe_vision/utils/image_utils.py delete mode 100644 src/mediapipe_vision/utils/mask_utils.py delete mode 100644 src/mediapipe_vision/utils/timestamp_provider.py delete mode 100644 src/utils/general_utils.py diff --git a/src/mediapipe_vision/utils/comfy_utils.py b/src/mediapipe_vision/utils/comfy_utils.py deleted file mode 100644 index 7c77950..0000000 --- a/src/mediapipe_vision/utils/comfy_utils.py +++ /dev/null @@ -1,7 +0,0 @@ -"""Utilities specific to ComfyUI integration.""" - -# Import from the new consolidated utilities -from ...utils.general import AlwaysEqualProxy - -# This file is maintained for backward compatibility -# New code should import directly from src.utils \ No newline at end of file diff --git a/src/mediapipe_vision/utils/image_utils.py b/src/mediapipe_vision/utils/image_utils.py deleted file mode 100644 index e1a825b..0000000 --- a/src/mediapipe_vision/utils/image_utils.py +++ /dev/null @@ -1,52 +0,0 @@ -"""Image utilities for MediaPipe Vision integration.""" - -# Import from the new consolidated utilities -from ...utils.image import convert_to_cv2, convert_to_tensor - -# This file is maintained for backward compatibility -# New code should import directly from src.utils - -import torch -import numpy as np -import cv2 - -def convert_to_cv2(tensor: torch.Tensor) -> list: - """Converts a ComfyUI IMAGE tensor (BHWC, float32, 0-1) to a list of cv2 images (BGR, uint8).""" - if tensor.ndim != 4 or tensor.shape[3] != 3: - raise ValueError(f"Input tensor must be BHWC with 3 channels, got shape: {tensor.shape}") - - # Convert entire batch to numpy, scale to 0-255, and convert to uint8 - images_np = tensor.cpu().numpy() - images_np = (images_np * 255).clip(0, 255).astype(np.uint8) - - # Convert RGB to BGR for cv2 - cv2_images = [cv2.cvtColor(img, cv2.COLOR_RGB2BGR) for img in images_np] - return cv2_images - -def convert_to_tensor(cv2_images) -> torch.Tensor: - """Converts cv2 image(s) (BGR, uint8) to a ComfyUI IMAGE tensor (BHWC, float32, 0-1). - - Args: - cv2_images: A single cv2 image or a list of cv2 images - """ - # Handle both single image and list of images - if not isinstance(cv2_images, list): - cv2_images = [cv2_images] - - # Process each image - np_images = [] - for cv2_image in cv2_images: - # Convert BGR to RGB - rgb_image = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB) - - # Scale to 0-1 - image_np = rgb_image.astype(np.float32) / 255.0 - np_images.append(image_np) - - # Stack all images into a batch - batch_np = np.stack(np_images, axis=0) - - # Convert to tensor (already has batch dimension) - tensor = torch.from_numpy(batch_np) - - return tensor \ No newline at end of file diff --git a/src/mediapipe_vision/utils/mask_utils.py b/src/mediapipe_vision/utils/mask_utils.py deleted file mode 100644 index c62b46c..0000000 --- a/src/mediapipe_vision/utils/mask_utils.py +++ /dev/null @@ -1,11 +0,0 @@ -# --- Helper Function --- -import torch -import numpy as np -import cv2 -from typing import List, Tuple -import logging -from ...utils.image import create_mask_from_points - -logger = logging.getLogger(__name__) - -# create_mask_from_points is now imported from utils.image \ No newline at end of file diff --git a/src/mediapipe_vision/utils/timestamp_provider.py b/src/mediapipe_vision/utils/timestamp_provider.py deleted file mode 100644 index 9d8e51d..0000000 --- a/src/mediapipe_vision/utils/timestamp_provider.py +++ /dev/null @@ -1,4 +0,0 @@ -from ...utils.timing import TimestampProvider - -# This file is maintained for backward compatibility -# New code should import directly from src.utils.timing \ No newline at end of file diff --git a/src/utils/general_utils.py b/src/utils/general_utils.py deleted file mode 100644 index de31bed..0000000 --- a/src/utils/general_utils.py +++ /dev/null @@ -1,4 +0,0 @@ -from .general import AlwaysEqualProxy - -# This file is maintained for backward compatibility -# New code should import directly from src.utils.general \ No newline at end of file From 7190738f942cdc2022c5f872a8bbc1d824feba43 Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Sat, 26 Apr 2025 10:52:11 -0400 Subject: [PATCH 08/13] update imports --- .../holistic_landmark/detector.py | 2 +- src/mediapipe_vision/image_embedding/detector.py | 3 ++- .../image_segmentation/segmenter.py | 2 +- .../interactive_segmentation/detector.py | 3 ++- src/mediapipe_vision/object_detection/detector.py | 2 +- src/mediapipe_vision/pose_landmark/detector.py | 2 +- src/mediapipe_vision/utils/__init__.py | 15 ++++++++------- src/mediapipe_vision/utils/delta_utils.py | 9 ++++++++- 8 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/mediapipe_vision/holistic_landmark/detector.py b/src/mediapipe_vision/holistic_landmark/detector.py index 5acb471..33b157c 100644 --- a/src/mediapipe_vision/holistic_landmark/detector.py +++ b/src/mediapipe_vision/holistic_landmark/detector.py @@ -12,7 +12,7 @@ from typing import List, Tuple, Optional, Dict, Any # Import needed types from ..types import LandmarkPoint, HolisticLandmarksResult -from ..utils.timestamp_provider import TimestampProvider +from ...utils.timing import TimestampProvider class HolisticLandmarkDetector: """Detects holistic landmarks combining face, pose and hand tracking. diff --git a/src/mediapipe_vision/image_embedding/detector.py b/src/mediapipe_vision/image_embedding/detector.py index 2a1c5f1..41aad69 100644 --- a/src/mediapipe_vision/image_embedding/detector.py +++ b/src/mediapipe_vision/image_embedding/detector.py @@ -7,7 +7,8 @@ from mediapipe.tasks.python.core.base_options import BaseOptions from typing import List, Optional # Import new types from ..types import ImageEmbedderResult -from ..utils.timestamp_provider import TimestampProvider # Import TimestampProvider +# Import TimestampProvider from the new location +from ...utils.timing import TimestampProvider class ImageEmbedder: """Generates image embeddings using MediaPipe ImageEmbedder.""" diff --git a/src/mediapipe_vision/image_segmentation/segmenter.py b/src/mediapipe_vision/image_segmentation/segmenter.py index 9d4cc8c..f78b91c 100644 --- a/src/mediapipe_vision/image_segmentation/segmenter.py +++ b/src/mediapipe_vision/image_segmentation/segmenter.py @@ -11,7 +11,7 @@ from mediapipe.tasks.python import vision from mediapipe.tasks.python.vision import ImageSegmenter import platform # Needed for OS check import logging -from ..utils.timestamp_provider import TimestampProvider # Import TimestampProvider +from ...utils.timing import TimestampProvider logger = logging.getLogger(__name__) diff --git a/src/mediapipe_vision/interactive_segmentation/detector.py b/src/mediapipe_vision/interactive_segmentation/detector.py index c9c1774..c9aafd4 100644 --- a/src/mediapipe_vision/interactive_segmentation/detector.py +++ b/src/mediapipe_vision/interactive_segmentation/detector.py @@ -1,3 +1,4 @@ +import logging import mediapipe as mp import numpy as np import torch @@ -11,7 +12,7 @@ from mediapipe.tasks.python.components.containers import keypoint from typing import List, Optional from ..types import PointOfInterest -from ..utils.timestamp_provider import TimestampProvider +from ...utils.timing import TimestampProvider import logging logger = logging.getLogger(__name__) diff --git a/src/mediapipe_vision/object_detection/detector.py b/src/mediapipe_vision/object_detection/detector.py index d5514e7..a4ab82b 100644 --- a/src/mediapipe_vision/object_detection/detector.py +++ b/src/mediapipe_vision/object_detection/detector.py @@ -7,7 +7,7 @@ from mediapipe.tasks.python.core.base_options import BaseOptions from typing import List # Import new types from ..types import ObjectDetectionResult, ObjectDetectionCategory, BoundingBox -from ..utils.timestamp_provider import TimestampProvider # Import TimestampProvider +from ...utils.timing import TimestampProvider class ObjectDetector: """Detects objects using MediaPipe ObjectDetector.""" diff --git a/src/mediapipe_vision/pose_landmark/detector.py b/src/mediapipe_vision/pose_landmark/detector.py index ae49bc6..b4e3c5e 100644 --- a/src/mediapipe_vision/pose_landmark/detector.py +++ b/src/mediapipe_vision/pose_landmark/detector.py @@ -7,7 +7,7 @@ from mediapipe.tasks.python.core.base_options import BaseOptions from typing import List, Tuple, Optional # Import new types from ..types import LandmarkPoint, PoseLandmarksResult -from ..utils.timestamp_provider import TimestampProvider # Import TimestampProvider +from ...utils.timing import TimestampProvider class PoseLandmarkDetector: """Detects pose landmarks in an image using MediaPipe PoseLandmarker.""" diff --git a/src/mediapipe_vision/utils/__init__.py b/src/mediapipe_vision/utils/__init__.py index 413dd9a..5505374 100644 --- a/src/mediapipe_vision/utils/__init__.py +++ b/src/mediapipe_vision/utils/__init__.py @@ -1,18 +1,19 @@ """Utility functions for MediaPipe Vision.""" -from .download_utils import download_model -from ...utils.image import convert_to_cv2, convert_to_tensor +# DEPRECATED: These imports are maintained only for backward compatibility. +# For new code, please import directly from src.utils + from ...utils.math import scale_value +from ...utils.image import convert_to_cv2, convert_to_tensor -# For backward compatibility with existing code +# Keep only the functions specific to mediapipe_vision +from .download_utils import download_model from .delta_utils import calculate_euclidean_delta -# Maintain backward compatibility with existing imports -# New code should import directly from src.utils - __all__ = [ "convert_to_cv2", "convert_to_tensor", "calculate_euclidean_delta", - "scale_value" + "scale_value", + "download_model" ] \ No newline at end of file diff --git a/src/mediapipe_vision/utils/delta_utils.py b/src/mediapipe_vision/utils/delta_utils.py index b7c0ea2..6642527 100644 --- a/src/mediapipe_vision/utils/delta_utils.py +++ b/src/mediapipe_vision/utils/delta_utils.py @@ -1,9 +1,16 @@ +# DEPRECATED: This file is maintained only for backward compatibility. +# For new code, please import directly from: +# src.utils.math + +# scale_value has been moved to src/utils/math.py +# Please update your imports. + import math from typing import Optional from ...utils.math import scale_value from ..types import LandmarkPoint # Assuming LandmarkPoint is in src/types.py - +#TODO: refactor to common after unified coordinate system def calculate_euclidean_delta(p1: Optional[LandmarkPoint], p2: Optional[LandmarkPoint]) -> Optional[float]: """Calculates the Euclidean distance between two LandmarkPoint objects.""" if p1 is None or p2 is None: From bfca61470fd1370b0447f47a091b4c86adea58af Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Sat, 26 Apr 2025 10:53:51 -0400 Subject: [PATCH 09/13] update rtn imports --- .../realtimenodes/controls/state_management_controls.py | 2 +- node_wrappers/realtimenodes/logic/logic.py | 2 +- node_wrappers/realtimenodes/utils/utility_controls.py | 2 +- node_wrappers/utils/misc_nodes.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/node_wrappers/realtimenodes/controls/state_management_controls.py b/node_wrappers/realtimenodes/controls/state_management_controls.py index 85ba291..09c0d82 100644 --- a/node_wrappers/realtimenodes/controls/state_management_controls.py +++ b/node_wrappers/realtimenodes/controls/state_management_controls.py @@ -1,6 +1,6 @@ from ....src.realtimenodes.control_base import ControlNodeBase import copy -from ....src.utils.general_utils import AlwaysEqualProxy +from ....src.utils.general import AlwaysEqualProxy class StateResetNode(ControlNodeBase): """Node that resets all control node states when triggered""" diff --git a/node_wrappers/realtimenodes/logic/logic.py b/node_wrappers/realtimenodes/logic/logic.py index 7bcdc91..7fcb23e 100644 --- a/node_wrappers/realtimenodes/logic/logic.py +++ b/node_wrappers/realtimenodes/logic/logic.py @@ -1,5 +1,5 @@ -from ....src.utils.general_utils import AlwaysEqualProxy from ....src.realtimenodes.control_base import ControlNodeBase +from ....src.utils.general import AlwaysEqualProxy class LazyCondition(ControlNodeBase): DESCRIPTION = "Uses lazy evaluation to truly skip execution of unused paths. Maintains state of the last value to circumvent feedback loops." diff --git a/node_wrappers/realtimenodes/utils/utility_controls.py b/node_wrappers/realtimenodes/utils/utility_controls.py index e6a298e..92d08e5 100644 --- a/node_wrappers/realtimenodes/utils/utility_controls.py +++ b/node_wrappers/realtimenodes/utils/utility_controls.py @@ -5,7 +5,7 @@ import numpy as np import cv2 import torch import random -from ....src.utils.general_utils import AlwaysEqualProxy +from ....src.utils.general import AlwaysEqualProxy # # Add package root to Python path # <-- REMOVED # sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from ....src.realtimenodes.control_base import ControlNodeBase diff --git a/node_wrappers/utils/misc_nodes.py b/node_wrappers/utils/misc_nodes.py index 7ce8959..d7ffcde 100644 --- a/node_wrappers/utils/misc_nodes.py +++ b/node_wrappers/utils/misc_nodes.py @@ -9,7 +9,7 @@ from PIL import Image, ImageFont, ImageDraw, ImageOps import nodes import random from torchvision import transforms -from ...src.utils.general_utils import AlwaysEqualProxy +from ...src.utils.general import AlwaysEqualProxy MAX_RESOLUTION = nodes.MAX_RESOLUTION # Get the same max resolution as core nodes class DTypeConverter: From 92f40a0f8c71f640f102677c094bf4671f111b4a Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Sat, 26 Apr 2025 10:54:04 -0400 Subject: [PATCH 10/13] update mpv imports --- .../mediapipe_vision/common/base_visualization_nodes.py | 2 +- .../mediapipe_vision/face/landmark/face_masking.py | 2 +- .../mediapipe_vision/hand/landmark/hand_landmark_masking.py | 4 ++-- .../location_landmark/universal_landmark_nodes.py | 6 +++--- .../object_detection/object_detection_visualization.py | 2 +- .../mediapipe_vision/pose/pose_landmark_masking.py | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/node_wrappers/mediapipe_vision/common/base_visualization_nodes.py b/node_wrappers/mediapipe_vision/common/base_visualization_nodes.py index 594fa0f..f258cd0 100644 --- a/node_wrappers/mediapipe_vision/common/base_visualization_nodes.py +++ b/node_wrappers/mediapipe_vision/common/base_visualization_nodes.py @@ -3,7 +3,7 @@ from typing import List, Dict, Tuple, Any, Optional, Type import cv2 import numpy as np -from ....src.mediapipe_vision.utils.image_utils import convert_to_cv2, convert_to_tensor +from ....src.utils.image import convert_to_cv2, convert_to_tensor logger = logging.getLogger(__name__) diff --git a/node_wrappers/mediapipe_vision/face/landmark/face_masking.py b/node_wrappers/mediapipe_vision/face/landmark/face_masking.py index 0832272..54dd39f 100644 --- a/node_wrappers/mediapipe_vision/face/landmark/face_masking.py +++ b/node_wrappers/mediapipe_vision/face/landmark/face_masking.py @@ -6,7 +6,7 @@ import logging from typing import List, Dict, Tuple from .....src.mediapipe_vision.types import LandmarkPoint -from .....src.mediapipe_vision.utils.mask_utils import create_mask_from_points +from .....src.utils.image import create_mask_from_points logger = logging.getLogger(__name__) _category = "Realtime Nodes/MediaPipe Vision/Face/FaceLandmark/Masking" diff --git a/node_wrappers/mediapipe_vision/hand/landmark/hand_landmark_masking.py b/node_wrappers/mediapipe_vision/hand/landmark/hand_landmark_masking.py index 041b04e..b5279e5 100644 --- a/node_wrappers/mediapipe_vision/hand/landmark/hand_landmark_masking.py +++ b/node_wrappers/mediapipe_vision/hand/landmark/hand_landmark_masking.py @@ -5,8 +5,8 @@ import logging from typing import List from .....src.mediapipe_vision.types import HandLandmarksResult -# Reusing the helper function from face masking -from .....src.mediapipe_vision.utils.mask_utils import create_mask_from_points +# Updated import path +from .....src.utils.image import create_mask_from_points logger = logging.getLogger(__name__) _category = "Realtime Nodes/MediaPipe Vision/Hand/HandLandmark/Masking" diff --git a/node_wrappers/mediapipe_vision/location_landmark/universal_landmark_nodes.py b/node_wrappers/mediapipe_vision/location_landmark/universal_landmark_nodes.py index b284201..b5b1e50 100644 --- a/node_wrappers/mediapipe_vision/location_landmark/universal_landmark_nodes.py +++ b/node_wrappers/mediapipe_vision/location_landmark/universal_landmark_nodes.py @@ -15,9 +15,9 @@ from ....src.mediapipe_vision.types import ( LandmarkPoint, FaceLandmarksResult, HandLandmarksResult, PoseLandmarksResult ) -# Re-import needed utils if not available globally -from ....src.mediapipe_vision.utils.delta_utils import scale_value -from ....src.mediapipe_vision.utils.comfy_utils import AlwaysEqualProxy +# Import from the new consolidated utilities +from ....src.utils.math import scale_value +from ....src.utils.general import AlwaysEqualProxy logger = logging.getLogger(__name__) diff --git a/node_wrappers/mediapipe_vision/object_detection/object_detection_visualization.py b/node_wrappers/mediapipe_vision/object_detection/object_detection_visualization.py index ab5df83..ba065cb 100644 --- a/node_wrappers/mediapipe_vision/object_detection/object_detection_visualization.py +++ b/node_wrappers/mediapipe_vision/object_detection/object_detection_visualization.py @@ -3,7 +3,7 @@ import torch import numpy as np import cv2 -from ....src.mediapipe_vision.utils.image_utils import convert_to_cv2, convert_to_tensor +from ....src.utils.image import convert_to_cv2, convert_to_tensor from ..common.base_visualization_nodes import BaseDetectionVisualizationNode import logging diff --git a/node_wrappers/mediapipe_vision/pose/pose_landmark_masking.py b/node_wrappers/mediapipe_vision/pose/pose_landmark_masking.py index e282345..6af580c 100644 --- a/node_wrappers/mediapipe_vision/pose/pose_landmark_masking.py +++ b/node_wrappers/mediapipe_vision/pose/pose_landmark_masking.py @@ -6,7 +6,7 @@ import logging from typing import List, Dict, Tuple from ....src.mediapipe_vision.types import PoseLandmarksResult -from ....src.mediapipe_vision.utils.mask_utils import create_mask_from_points +from ....src.utils.image import create_mask_from_points # Removed GetImageDimensionsNode import logger = logging.getLogger(__name__) From af7ac36c6d7df2087fe0dd80807e6d05918ad719 Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Sat, 26 Apr 2025 11:05:22 -0400 Subject: [PATCH 11/13] straggle imports --- node_wrappers/mediapipe_vision/face/landmark/blendshape.py | 2 +- node_wrappers/mediapipe_vision/face/landmark/head_pose.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/node_wrappers/mediapipe_vision/face/landmark/blendshape.py b/node_wrappers/mediapipe_vision/face/landmark/blendshape.py index 61a79b1..6d306f2 100644 --- a/node_wrappers/mediapipe_vision/face/landmark/blendshape.py +++ b/node_wrappers/mediapipe_vision/face/landmark/blendshape.py @@ -7,7 +7,7 @@ from .....src.mediapipe_vision.utils.misc_utils import get_blendshape_categories # Import base trigger/control logic if we adapt base classes later, or implement directly for now from ...location_landmark.universal_landmark_nodes import FLOAT_EQUALITY_TOLERANCE # For trigger node comparisons -from .....src.mediapipe_vision.utils.delta_utils import scale_value +from .....src.utils.math import scale_value logger = logging.getLogger(__name__) diff --git a/node_wrappers/mediapipe_vision/face/landmark/head_pose.py b/node_wrappers/mediapipe_vision/face/landmark/head_pose.py index 4a0b891..6130c2a 100644 --- a/node_wrappers/mediapipe_vision/face/landmark/head_pose.py +++ b/node_wrappers/mediapipe_vision/face/landmark/head_pose.py @@ -5,7 +5,7 @@ from scipy.spatial.transform import Rotation as R from typing import Optional, List, Any, Tuple, Dict from .....src.mediapipe_vision.types import TRANSFORM_MATRIX_LIST -from .....src.mediapipe_vision.utils.delta_utils import scale_value +from .....src.utils.math import scale_value from ...location_landmark.universal_landmark_nodes import FLOAT_EQUALITY_TOLERANCE # For trigger node comparisons logger = logging.getLogger(__name__) From 15f7389be3a49944f02def3b39b1274936b0bb1d Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Sat, 26 Apr 2025 11:06:41 -0400 Subject: [PATCH 12/13] blendshape utils --- node_wrappers/mediapipe_vision/face/landmark/blendshape.py | 2 +- .../utils/{misc_utils.py => blendshape_utils.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/mediapipe_vision/utils/{misc_utils.py => blendshape_utils.py} (100%) diff --git a/node_wrappers/mediapipe_vision/face/landmark/blendshape.py b/node_wrappers/mediapipe_vision/face/landmark/blendshape.py index 6d306f2..135ac77 100644 --- a/node_wrappers/mediapipe_vision/face/landmark/blendshape.py +++ b/node_wrappers/mediapipe_vision/face/landmark/blendshape.py @@ -3,7 +3,7 @@ import logging from typing import Optional, List, Any, Dict, Tuple from .....src.mediapipe_vision.types import BLENDSHAPES_LIST # Updated type alias -from .....src.mediapipe_vision.utils.misc_utils import get_blendshape_categories # Utility to get all category names +from .....src.mediapipe_vision.utils.blendshape_utils import get_blendshape_categories # Utility to get all category names # Import base trigger/control logic if we adapt base classes later, or implement directly for now from ...location_landmark.universal_landmark_nodes import FLOAT_EQUALITY_TOLERANCE # For trigger node comparisons diff --git a/src/mediapipe_vision/utils/misc_utils.py b/src/mediapipe_vision/utils/blendshape_utils.py similarity index 100% rename from src/mediapipe_vision/utils/misc_utils.py rename to src/mediapipe_vision/utils/blendshape_utils.py From 9dc4292715c17a835480348c8bbd4a2d2701e5bf Mon Sep 17 00:00:00 2001 From: RyanOnTheInside <7623207+ryanontheinside@users.noreply.github.com> Date: Sat, 26 Apr 2025 12:16:57 -0400 Subject: [PATCH 13/13] timestamp provider import --- src/mediapipe_vision/face_detection/detector.py | 2 +- src/mediapipe_vision/face_landmark/detector.py | 2 +- src/mediapipe_vision/face_stylization/detector.py | 2 +- src/mediapipe_vision/gesture_recognition/detector.py | 2 +- src/mediapipe_vision/hand_landmark/detector.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mediapipe_vision/face_detection/detector.py b/src/mediapipe_vision/face_detection/detector.py index 4a8b6e2..0e40e6e 100644 --- a/src/mediapipe_vision/face_detection/detector.py +++ b/src/mediapipe_vision/face_detection/detector.py @@ -12,7 +12,7 @@ from mediapipe.tasks.python.core.base_options import BaseOptions from typing import List, Tuple # Import new types from ..types import FaceDetectionResult, BoundingBox, FaceKeypoint -from ..utils.timestamp_provider import TimestampProvider # Import from utils +from ...utils.timing import TimestampProvider # Import from utils class FaceDetector: """Detects faces in an image using MediaPipe FaceDetector.""" diff --git a/src/mediapipe_vision/face_landmark/detector.py b/src/mediapipe_vision/face_landmark/detector.py index 90ce5fa..73b448d 100644 --- a/src/mediapipe_vision/face_landmark/detector.py +++ b/src/mediapipe_vision/face_landmark/detector.py @@ -7,7 +7,7 @@ from mediapipe.tasks.python.core.base_options import BaseOptions from typing import List, Tuple, Optional, Dict # Import new types from ..types import LandmarkPoint, FaceLandmarksResult -from ..utils.timestamp_provider import TimestampProvider # Import TimestampProvider +from ...utils.timing import TimestampProvider # Import TimestampProvider class FaceLandmarkDetector: """Detects face landmarks and blendshapes using MediaPipe FaceLandmarker.""" diff --git a/src/mediapipe_vision/face_stylization/detector.py b/src/mediapipe_vision/face_stylization/detector.py index 9926d0f..706a0de 100644 --- a/src/mediapipe_vision/face_stylization/detector.py +++ b/src/mediapipe_vision/face_stylization/detector.py @@ -4,7 +4,7 @@ import torch from mediapipe.tasks import python from mediapipe.tasks.python import vision from typing import List, Optional -from ..utils.timestamp_provider import TimestampProvider +from ...utils.timing import TimestampProvider class FaceStylizer: """Applies stylization to faces using MediaPipe FaceStylizer.""" diff --git a/src/mediapipe_vision/gesture_recognition/detector.py b/src/mediapipe_vision/gesture_recognition/detector.py index 200692a..565274a 100644 --- a/src/mediapipe_vision/gesture_recognition/detector.py +++ b/src/mediapipe_vision/gesture_recognition/detector.py @@ -7,7 +7,7 @@ from mediapipe.tasks.python.core.base_options import BaseOptions from typing import List # Import new types from ..types import GestureRecognitionResult, GestureCategory -from ..utils.timestamp_provider import TimestampProvider # Import TimestampProvider +from ...utils.timing import TimestampProvider # Import TimestampProvider class GestureRecognizer: """Recognizes hand gestures using MediaPipe GestureRecognizer.""" diff --git a/src/mediapipe_vision/hand_landmark/detector.py b/src/mediapipe_vision/hand_landmark/detector.py index 2b3eeb0..693764d 100644 --- a/src/mediapipe_vision/hand_landmark/detector.py +++ b/src/mediapipe_vision/hand_landmark/detector.py @@ -7,7 +7,7 @@ from mediapipe.tasks.python.core.base_options import BaseOptions from typing import List, Tuple, Optional # Import new types from ..types import LandmarkPoint, HandLandmarksResult -from ..utils.timestamp_provider import TimestampProvider # Import TimestampProvider +from ...utils.timing import TimestampProvider # Import TimestampProvider class HandLandmarkDetector: """Detects hand landmarks using MediaPipe HandLandmarker."""