From 2fed8ae0c3e18ea79d8d6c04cbd35cc72db5c213 Mon Sep 17 00:00:00 2001 From: SkalskiP Date: Wed, 18 Oct 2023 23:10:36 +0200 Subject: [PATCH] test --- supervision/draw/utils.py | 68 +++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/supervision/draw/utils.py b/supervision/draw/utils.py index 56740377..721836f3 100644 --- a/supervision/draw/utils.py +++ b/supervision/draw/utils.py @@ -1,3 +1,4 @@ +import os from typing import Optional, Union import cv2 @@ -171,40 +172,59 @@ def draw_text( def draw_image( - scene: np.ndarray, image: Union[str, np.ndarray], opacity: float, rect: Rect + scene: np.ndarray, + image: Union[str, np.ndarray], + opacity: float, + rect: Rect ) -> np.ndarray: """ Draws an image onto a given scene with specified opacity and dimensions. + + Args: + scene (np.ndarray): Background image where the new image will be drawn. + image (Union[str, np.ndarray]): Image to draw. + opacity (float): Opacity of the image to be drawn. + rect (Rect): Rectangle specifying where to draw the image. + + Returns: + np.ndarray: The updated scene. + + Raises: + FileNotFoundError: If the image path does not exist. + ValueError: For invalid opacity or rectangle dimensions. """ - # Load image if a path is provided + # Validate and load image if isinstance(image, str): + if not os.path.exists(image): + raise FileNotFoundError(f"Image path ('{image}') does not exist.") image = cv2.imread(image, cv2.IMREAD_UNCHANGED) - # Resize the image + # Validate opacity + if not 0.0 <= opacity <= 1.0: + raise ValueError("Opacity must be between 0.0 and 1.0.") + + # Validate rectangle dimensions + if rect.x < 0 or rect.y < 0 or \ + rect.x + rect.width > scene.shape[1] or rect.y + rect.height > scene.shape[ + 0]: + raise ValueError("Invalid rectangle dimensions.") + + # Resize and isolate alpha channel image = cv2.resize(image, (rect.width, rect.height)) + alpha_channel = image[:, :, 3] if image.shape[2] == 4 else np.ones( + (rect.height, rect.width), dtype=image.dtype) * 255 + alpha_scaled = cv2.convertScaleAbs(alpha_channel * opacity) - # Separate the alpha channel if present - if image.shape[2] == 4: - alpha_channel = image[:, :, 3] - image = image[:, :, :3] - else: - alpha_channel = np.ones((rect.height, rect.width), dtype=np.uint8) * 255 + # Perform blending + scene_roi = scene[rect.y:rect.y + rect.height, rect.x:rect.x + rect.width] + alpha_float = alpha_scaled.astype(np.float32) / 255.0 + blended_roi = cv2.convertScaleAbs( + (1 - alpha_float[..., np.newaxis]) * scene_roi + alpha_float[ + ..., np.newaxis] * image[:, :, :3] + ) - # Apply opacity to the alpha channel - alpha_channel = cv2.convertScaleAbs(alpha_channel * opacity) - - # Get the ROI from the scene - scene_roi = scene[rect.y : rect.y + rect.height, rect.x : rect.x + rect.width] - - # Manually apply alpha blending - alpha_float = alpha_channel.astype(np.float32) / 255.0 - blended_roi = ( - (1.0 - alpha_float[..., np.newaxis]) * scene_roi.astype(np.float32) - ) + (alpha_float[..., np.newaxis] * image.astype(np.float32)) - blended_roi = blended_roi.astype(np.uint8) - - # Insert blended ROI back into the scene - scene[rect.y : rect.y + rect.height, rect.x : rect.x + rect.width] = blended_roi + # Update the scene + scene[rect.y:rect.y + rect.height, rect.x:rect.x + rect.width] = blended_roi return scene