Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| from PIL import Image | |
| from typing import Tuple, Any, Dict, List | |
| # Lazy imports to speed cold start | |
| clf = None | |
| yolo_severity = None | |
| def _load_models(): | |
| global clf, yolo_severity | |
| if clf is None: | |
| from transformers import pipeline | |
| # Image classification (damage types) | |
| clf = pipeline("image-classification", model="beingamit99/car_damage_detection") | |
| if yolo_severity is None: | |
| from ultralytics import YOLO | |
| # YOLOv8 severity detector (Light/Moderate/Severe) | |
| yolo_severity = YOLO("nezahatkorkmaz/car-damage-level-detection-yolov8") | |
| def analyze(img: Image.Image) -> Tuple[Dict[str, Any], Image.Image, Any]: | |
| """ | |
| Returns: | |
| - JSON summary (gate + top labels + detections) | |
| - Overlay image with boxes | |
| - Raw YOLO JSON (string or dict) | |
| """ | |
| _load_models() | |
| # --- Gate using classifier --- | |
| # If model has a 'no_damage' label use it; otherwise treat max score < 0.5 as "no damage" | |
| preds = sorted(clf(img), key=lambda x: x["score"], reverse=True) | |
| top = preds[0] if preds else {"label": "unknown", "score": 0.0} | |
| label_lower = top["label"].lower() | |
| if "no" in label_lower and "damage" in label_lower: | |
| gate = False | |
| else: | |
| gate = top["score"] >= 0.5 | |
| if not gate: | |
| return {"gate": "No visible damage", "classification_top": top}, img, {"detections": []} | |
| # --- Top-3 labels for type --- | |
| top3 = [{"label": p["label"], "score": float(p["score"])} for p in preds[:3]] | |
| # --- YOLO severity boxes --- | |
| yres = yolo_severity.predict(img) | |
| result = yres[0] | |
| plotted = result.plot() # numpy array with drawn boxes | |
| dets = [] | |
| if result.boxes is not None and len(result.boxes) > 0: | |
| # class names if available | |
| names = result.names if hasattr(result, "names") else {} | |
| for i in range(len(result.boxes)): | |
| b = result.boxes[i] | |
| xyxy = b.xyxy[0].tolist() | |
| conf = float(b.conf[0].item()) | |
| cls_id = int(b.cls[0].item()) | |
| cls_name = names.get(cls_id, str(cls_id)) | |
| dets.append({ | |
| "bbox_xyxy": [float(x) for x in xyxy], | |
| "confidence": conf, | |
| "class_id": cls_id, | |
| "class_name": cls_name | |
| }) | |
| summary = {"gate": "Damaged", "classification_top3": top3, "detections": dets} | |
| try: | |
| raw_json = result.tojson() # string | |
| except Exception: | |
| raw_json = {"error": "tojson failed"} | |
| from PIL import Image as _Image | |
| return summary, _Image.fromarray(plotted), raw_json | |
| demo = gr.Interface( | |
| fn=analyze, | |
| inputs=gr.Image(type="pil", label="Upload a car photo"), | |
| outputs=[ | |
| gr.JSON(label="Results (gate + top labels + detections)"), | |
| gr.Image(label="Detections Overlay"), | |
| gr.JSON(label="Raw YOLO JSON") | |
| ], | |
| title="Car Damage Inspector", | |
| description=( | |
| "Fast, open-source car damage analysis.\n" | |
| "- Step 1: Classify damage type (ViT).\n" | |
| "- Step 2: Detect severity with YOLOv8 (boxes).\n" | |
| "Models: beingamit99/car_damage_detection, nezahatkorkmaz/car-damage-level-detection-yolov8." | |
| ), | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |