viswanani commited on
Commit
04a5678
·
verified ·
1 Parent(s): 94332c9

Upload 3 files

Browse files
Files changed (3) hide show
  1. car_core/README.md +38 -0
  2. car_core/app.py +95 -0
  3. car_core/requirements.txt +12 -0
car_core/README.md ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # Car Damage Inspector (Hugging Face-ready)
3
+
4
+ An open-source, one-file Gradio app that:
5
+ 1) Classifies car damage type with a transformer classifier.
6
+ 2) Detects damage regions & severity (Light/Moderate/Severe) with YOLOv8.
7
+
8
+ **Models used**
9
+ - `beingamit99/car_damage_detection` (image classification)
10
+ - `nezahatkorkmaz/car-damage-level-detection-yolov8` (YOLOv8 detector)
11
+
12
+ ## Quickstart (local)
13
+
14
+ ```bash
15
+ python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
16
+ pip install -r requirements.txt
17
+ python app.py
18
+ ```
19
+
20
+ Open the Gradio link shown in the terminal and upload a car photo.
21
+
22
+ ## Deploy to Hugging Face Spaces
23
+
24
+ 1. Create a new **Space** (Python).
25
+ 2. Upload these three files:
26
+ - `app.py`
27
+ - `requirements.txt`
28
+ - `README.md`
29
+ 3. The Space will auto-build, download models on first run, and serve the UI.
30
+
31
+ ## Notes
32
+ - First inference will download model weights; allow a little time.
33
+ - Gate logic is heuristic: if the top classification score < 0.5 (or model predicts an explicit *no-damage* class), the app returns "No visible damage".
34
+ - Replace/extend with your own gate (e.g., a dedicated binary model) if desired.
35
+ - Outputs:
36
+ - **JSON** with top-3 labels and YOLO detections,
37
+ - **Overlay image** with bounding boxes,
38
+ - **Raw YOLO JSON** (for debugging/integration).
car_core/app.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from PIL import Image
4
+ from typing import Tuple, Any, Dict, List
5
+
6
+ # Lazy imports to speed cold start
7
+ clf = None
8
+ yolo_severity = None
9
+
10
+ def _load_models():
11
+ global clf, yolo_severity
12
+ if clf is None:
13
+ from transformers import pipeline
14
+ # Image classification (damage types)
15
+ clf = pipeline("image-classification", model="beingamit99/car_damage_detection")
16
+ if yolo_severity is None:
17
+ from ultralytics import YOLO
18
+ # YOLOv8 severity detector (Light/Moderate/Severe)
19
+ yolo_severity = YOLO("nezahatkorkmaz/car-damage-level-detection-yolov8")
20
+
21
+ def analyze(img: Image.Image) -> Tuple[Dict[str, Any], Image.Image, Any]:
22
+ """
23
+ Returns:
24
+ - JSON summary (gate + top labels + detections)
25
+ - Overlay image with boxes
26
+ - Raw YOLO JSON (string or dict)
27
+ """
28
+ _load_models()
29
+
30
+ # --- Gate using classifier ---
31
+ # If model has a 'no_damage' label use it; otherwise treat max score < 0.5 as "no damage"
32
+ preds = sorted(clf(img), key=lambda x: x["score"], reverse=True)
33
+ top = preds[0] if preds else {"label": "unknown", "score": 0.0}
34
+ label_lower = top["label"].lower()
35
+ if "no" in label_lower and "damage" in label_lower:
36
+ gate = False
37
+ else:
38
+ gate = top["score"] >= 0.5
39
+
40
+ if not gate:
41
+ return {"gate": "No visible damage", "classification_top": top}, img, {"detections": []}
42
+
43
+ # --- Top-3 labels for type ---
44
+ top3 = [{"label": p["label"], "score": float(p["score"])} for p in preds[:3]]
45
+
46
+ # --- YOLO severity boxes ---
47
+ yres = yolo_severity.predict(img)
48
+ result = yres[0]
49
+ plotted = result.plot() # numpy array with drawn boxes
50
+
51
+ dets = []
52
+ if result.boxes is not None and len(result.boxes) > 0:
53
+ # class names if available
54
+ names = result.names if hasattr(result, "names") else {}
55
+ for i in range(len(result.boxes)):
56
+ b = result.boxes[i]
57
+ xyxy = b.xyxy[0].tolist()
58
+ conf = float(b.conf[0].item())
59
+ cls_id = int(b.cls[0].item())
60
+ cls_name = names.get(cls_id, str(cls_id))
61
+ dets.append({
62
+ "bbox_xyxy": [float(x) for x in xyxy],
63
+ "confidence": conf,
64
+ "class_id": cls_id,
65
+ "class_name": cls_name
66
+ })
67
+
68
+ summary = {"gate": "Damaged", "classification_top3": top3, "detections": dets}
69
+ try:
70
+ raw_json = result.tojson() # string
71
+ except Exception:
72
+ raw_json = {"error": "tojson failed"}
73
+
74
+ from PIL import Image as _Image
75
+ return summary, _Image.fromarray(plotted), raw_json
76
+
77
+ demo = gr.Interface(
78
+ fn=analyze,
79
+ inputs=gr.Image(type="pil", label="Upload a car photo"),
80
+ outputs=[
81
+ gr.JSON(label="Results (gate + top labels + detections)"),
82
+ gr.Image(label="Detections Overlay"),
83
+ gr.JSON(label="Raw YOLO JSON")
84
+ ],
85
+ title="Car Damage Inspector",
86
+ description=(
87
+ "Fast, open-source car damage analysis.\n"
88
+ "- Step 1: Classify damage type (ViT).\n"
89
+ "- Step 2: Detect severity with YOLOv8 (boxes).\n"
90
+ "Models: beingamit99/car_damage_detection, nezahatkorkmaz/car-damage-level-detection-yolov8."
91
+ ),
92
+ )
93
+
94
+ if __name__ == "__main__":
95
+ demo.launch()
car_core/requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # Core app
3
+ gradio==4.44.0
4
+ pillow>=10.3.0
5
+
6
+ # Models
7
+ transformers>=4.41.0
8
+ torch>=2.1.0
9
+ torchvision>=0.16.0
10
+
11
+ # YOLO
12
+ ultralytics>=8.3.0