Team Ai
Apppublic

SahilCodevally/codevally-vision-language-action

sourceHugging Faceotherupdated 7mo agoView on Hugging Face
0likes
detector.py135 linesDownload Raw Back to vision
1"""2Vision Module — Object detection using YOLOv8.3 4Wraps the Ultralytics YOLO model to detect objects in images and return5structured results. The model is loaded **once** in the constructor and6reused for all subsequent detections.7"""8 9import logging10from typing import Any11 12import numpy as np13 14logger = logging.getLogger(__name__)15 16 17class ObjectDetector:18    """19    Detects objects in images using a pretrained YOLOv8 model.20 21    Attributes:22        model: The loaded YOLO model instance (cached after first load).23    """24 25    def __init__(self, model_name: str = "yolov8n.pt", confidence: float = 0.25):26        """27        Initialize the detector and load the YOLO model.28 29        Args:30            model_name: Name or path of the YOLO model weights.31            confidence: Minimum confidence threshold for detections.32        """33        self.model_name = model_name34        self.confidence = confidence35        self.model = None36 37        self._load_model()38 39    def _load_model(self) -> None:40        """Load the YOLO model. Called once during initialization."""41        try:42            from ultralytics import YOLO43 44            logger.info("Loading YOLO model: %s", self.model_name)45            self.model = YOLO(self.model_name)46            logger.info("YOLO model loaded successfully.")47        except Exception as exc:48            logger.error("Failed to load YOLO model '%s': %s", self.model_name, exc)49            raise RuntimeError(50                f"Could not load YOLO model '{self.model_name}'. "51                f"Ensure ultralytics is installed and the model file is accessible."52            ) from exc53 54    def detect(self, image: np.ndarray) -> list[dict[str, Any]]:55        """56        Run object detection on an image.57 58        Args:59            image: Input image as a NumPy array (H, W, C) in BGR or RGB format.60 61        Returns:62            List of detected objects, each containing:63                - ``label`` (str): Class name.64                - ``confidence`` (float): Detection confidence (0-1).65                - ``bbox`` (list[int]): Bounding box as [x1, y1, x2, y2].66 67        Raises:68            ValueError: If the input image is invalid.69            RuntimeError: If the model is not loaded.70        """71        if self.model is None:72            raise RuntimeError("YOLO model is not loaded.")73 74        if image is None or not isinstance(image, np.ndarray):75            raise ValueError("Invalid image: expected a NumPy ndarray.")76 77        if image.ndim < 2:78            raise ValueError(79                f"Invalid image dimensions: expected 2D or 3D array, "80                f"got {image.ndim}D."81            )82 83        logger.info(84            "Running detection on image of shape %s with confidence=%.2f",85            image.shape,86            self.confidence,87        )88 89        try:90            results = self.model(image, conf=self.confidence, verbose=False)91        except Exception as exc:92            logger.error("YOLO inference failed: %s", exc)93            return []94 95        detections = self._parse_results(results)96        logger.info("Detected %d objects.", len(detections))97        return detections98 99    def _parse_results(self, results: Any) -> list[dict[str, Any]]:100        """101        Parse YOLO results into a structured list of detections.102 103        Args:104            results: Raw YOLO results object.105 106        Returns:107            Structured list of detection dictionaries.108        """109        detections: list[dict[str, Any]] = []110 111        for result in results:112            boxes = result.boxes113            if boxes is None:114                continue115 116            for i in range(len(boxes)):117                try:118                    bbox = boxes.xyxy[i].cpu().numpy().tolist()119                    confidence = float(boxes.conf[i].cpu().numpy())120                    class_id = int(boxes.cls[i].cpu().numpy())121                    label = result.names.get(class_id, f"class_{class_id}")122 123                    detections.append(124                        {125                            "label": label,126                            "confidence": round(confidence, 4),127                            "bbox": [int(coord) for coord in bbox],128                        }129                    )130                except (IndexError, KeyError, AttributeError) as exc:131                    logger.warning("Failed to parse detection %d: %s", i, exc)132                    continue133 134        return detections135