| from ultralytics import YOLO |
| import cv2 |
| import numpy as np |
|
|
| from core.config import settings |
| from core.logger import logger |
|
|
|
|
| class DefectInspector: |
| """ |
| Handles model inference and defect extraction. |
| """ |
|
|
| def __init__(self, model_path: str): |
| self.model = YOLO(model_path) |
| logger.info(f"Model loaded from: {model_path}") |
|
|
| def inspect_image(self, image: np.ndarray): |
| """ |
| Run inference and extract defect information. |
| """ |
|
|
| try: |
| results = self.model( |
| image, |
| conf=settings.CONF_THRESHOLD, |
| imgsz=settings.IMAGE_SIZE, |
| verbose=False |
| ) |
|
|
| result = results[0] |
| defects = [] |
|
|
| if result.masks is None: |
| return defects |
|
|
| masks = result.masks.data.cpu().numpy() |
| classes = result.boxes.cls.cpu().numpy() |
| confidences = result.boxes.conf.cpu().numpy() |
|
|
| height, width = image.shape[:2] |
| image_area = height * width |
|
|
| for i, (mask, cls_id) in enumerate(zip(masks, classes)): |
|
|
| confidence = float(confidences[i]) |
|
|
| if confidence < settings.SECONDARY_CONF_THRESHOLD: |
| continue |
|
|
| |
| |
| |
| mask = cv2.resize(mask, (width, height)) |
| mask = (mask > 0.3).astype("uint8") * 255 |
|
|
| kernel = np.ones((3, 3), np.uint8) |
| mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) |
|
|
| |
| |
| |
| contours, _ = cv2.findContours( |
| mask, |
| cv2.RETR_EXTERNAL, |
| cv2.CHAIN_APPROX_SIMPLE |
| ) |
|
|
| if not contours: |
| continue |
|
|
| |
| largest_contour = max(contours, key=cv2.contourArea) |
|
|
| |
| epsilon = 0.01 * cv2.arcLength(largest_contour, True) |
| largest_contour = cv2.approxPolyDP(largest_contour, epsilon, True) |
|
|
| cnt = largest_contour |
|
|
| area = cv2.contourArea(cnt) |
|
|
| if area < settings.MIN_DEFECT_AREA: |
| continue |
|
|
| x, y, w, h = cv2.boundingRect(cnt) |
|
|
| length = max(w, h) |
| width_def = min(w, h) |
|
|
| area_ratio = area / image_area |
|
|
| if area_ratio > settings.MAX_AREA_RATIO: |
| continue |
|
|
| defects.append({ |
| "class_id": int(cls_id), |
| "confidence": confidence, |
| "area_pixels": float(area), |
| "length_pixels": float(length), |
| "width_pixels": float(width_def), |
| "area_ratio": float(area_ratio), |
| "bbox": (x, y, w, h), |
| "contour": cnt |
| }) |
|
|
| return defects |
|
|
| except Exception as e: |
| logger.error(f"Inference failed: {e}") |
| return [] |