from typing import Dict, List, Tuple, Union import cv2 import numpy as np from inference.core.entities.requests.inference import ( InstanceSegmentationInferenceRequest, KeypointsDetectionInferenceRequest, ObjectDetectionInferenceRequest, ) from inference.core.entities.responses.inference import ( InstanceSegmentationPrediction, Keypoint, KeypointsPrediction, ObjectDetectionInferenceResponse, ObjectDetectionPrediction, Point, ) from inference.core.utils.image_utils import load_image_rgb, np_image_to_base64 def draw_detection_predictions( inference_request: Union[ ObjectDetectionInferenceRequest, InstanceSegmentationInferenceRequest, KeypointsDetectionInferenceRequest, ], inference_response: Union[ ObjectDetectionInferenceResponse, InstanceSegmentationPrediction, KeypointsPrediction, ], colors: Dict[str, str], ) -> bytes: image = load_image_rgb(inference_request.image) for box in inference_response.predictions: color = tuple( int(colors.get(box.class_name, "#4892EA")[i : i + 2], 16) for i in (1, 3, 5) ) image = draw_bbox( image=image, box=box, color=color, thickness=inference_request.visualization_stroke_width, ) if hasattr(box, "points"): image = draw_instance_segmentation_points( image=image, points=box.points, color=color, thickness=inference_request.visualization_stroke_width, ) if hasattr(box, "keypoints"): draw_keypoints( image=image, keypoints=box.keypoints, color=color, thickness=inference_request.visualization_stroke_width, ) if inference_request.visualization_labels: image = draw_labels( image=image, box=box, color=color, ) return np_image_to_base64(image=image) def draw_bbox( image: np.ndarray, box: ObjectDetectionPrediction, color: Tuple[int, ...], thickness: int, ) -> np.ndarray: left_top, right_bottom = bbox_to_points(box=box) return cv2.rectangle( image, left_top, right_bottom, color=color, thickness=thickness, ) def draw_instance_segmentation_points( image: np.ndarray, points: List[Point], color: Tuple[int, ...], thickness: int, ) -> np.ndarray: points_array = np.array([(int(p.x), int(p.y)) for p in points], np.int32) if len(points) > 2: image = cv2.polylines( image, [points_array], isClosed=True, color=color, thickness=thickness, ) return image def draw_keypoints( image: np.ndarray, keypoints: List[Keypoint], color: Tuple[int, ...], thickness: int, ) -> None: for keypoint in keypoints: center_coordinates = (round(keypoint.x), round(keypoint.y)) image = cv2.circle( image, center_coordinates, thickness, color, -1, ) def draw_labels( image: np.ndarray, box: Union[ObjectDetectionPrediction, InstanceSegmentationPrediction], color: Tuple[int, ...], ) -> np.ndarray: (x1, y1), _ = bbox_to_points(box=box) text = f"{box.class_name} {box.confidence:.2f}" (text_width, text_height), _ = cv2.getTextSize( text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1 ) button_size = (text_width + 20, text_height + 20) button_img = np.full( (button_size[1], button_size[0], 3), color[::-1], dtype=np.uint8 ) cv2.putText( button_img, text, (10, 10 + text_height), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1, ) end_x = min(x1 + button_size[0], image.shape[1]) end_y = min(y1 + button_size[1], image.shape[0]) image[y1:end_y, x1:end_x] = button_img[: end_y - y1, : end_x - x1] return image def bbox_to_points( box: Union[ObjectDetectionPrediction, InstanceSegmentationPrediction], ) -> Tuple[Tuple[int, int], Tuple[int, int]]: x1 = int(box.x - box.width / 2) x2 = int(box.x + box.width / 2) y1 = int(box.y - box.height / 2) y2 = int(box.y + box.height / 2) return (x1, y1), (x2, y2)