therealestcoder commited on
Commit
e9b55b6
Β·
verified Β·
1 Parent(s): 42c5773

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +133 -0
app.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Gradio Space β€” Paint Defect Detector."""
2
+ from __future__ import annotations
3
+
4
+ import os
5
+ import sys
6
+ import tempfile
7
+ from pathlib import Path
8
+
9
+ import cv2
10
+ import gradio as gr
11
+ import numpy as np
12
+ import torch
13
+ from PIL import Image
14
+
15
+ # ── paths ──────────────────────────────────────────────────────────────────
16
+ ROOT = Path(__file__).resolve().parent
17
+ sys.path.insert(0, str(ROOT))
18
+
19
+ from src import config as C
20
+ from src.infer import load_model, predict_image, render_visualization
21
+
22
+ # ── model (lazy) ───────────────────────────────────────────────────────────
23
+ _device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
24
+ _model = None
25
+
26
+ CHECKPOINT = ROOT / "checkpoints" / "best.pt"
27
+
28
+
29
+ def _get_model():
30
+ global _model
31
+ if _model is None:
32
+ if not CHECKPOINT.exists():
33
+ raise gr.Error(
34
+ "No trained checkpoint found at checkpoints/best.pt. "
35
+ "Please train the model first and upload the checkpoint."
36
+ )
37
+ _model = load_model(CHECKPOINT, device=_device)
38
+ return _model
39
+
40
+
41
+ # ── inference ──────────────────────────────────────────────────────────────
42
+
43
+ def run_inference(image: np.ndarray, vin: str, threshold: float) -> tuple:
44
+ if image is None:
45
+ return None, "⚠️ Please upload an image.", ""
46
+
47
+ # Convert RGB (Gradio) β†’ BGR (OpenCV)
48
+ bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
49
+
50
+ try:
51
+ model = _get_model()
52
+ except gr.Error as e:
53
+ return None, str(e), ""
54
+
55
+ result = predict_image(bgr, model, _device, threshold=threshold)
56
+ vis_bgr = render_visualization(result)
57
+ vis_rgb = cv2.cvtColor(vis_bgr, cv2.COLOR_BGR2RGB)
58
+
59
+ # ── verdict text ──────────────────────────────────────────────────────
60
+ verdict = "πŸ”΄ DEFECT DETECTED" if result["is_defect"] else "🟒 NO DEFECT β€” OK"
61
+ vin_line = f"**VIN:** {vin.strip()}\n\n" if vin.strip() else ""
62
+ summary = (
63
+ f"{vin_line}"
64
+ f"**Verdict:** {verdict}\n\n"
65
+ f"**Defect ratio:** {result['defect_ratio']*100:.2f}%\n\n"
66
+ f"**Max patch probability:** {result['max_prob']:.3f}\n\n"
67
+ f"**Defect regions found:** {len(result['boxes'])}\n\n"
68
+ f"**Panel size:** {result['panel_size']['w']} Γ— {result['panel_size']['h']} px"
69
+ )
70
+
71
+ # ── boxes table ───────────────────────────────────────────────────────
72
+ if result["boxes"]:
73
+ rows = "\n".join(
74
+ f"| {i+1} | {b['x']},{b['y']} | {b['w']}Γ—{b['h']} | {b['confidence']:.3f} |"
75
+ for i, b in enumerate(result["boxes"])
76
+ )
77
+ table = (
78
+ "### Defect Regions\n"
79
+ "| # | Position (x,y) | Size (wΓ—h) | Confidence |\n"
80
+ "|---|----------------|------------|------------|\n"
81
+ + rows
82
+ )
83
+ else:
84
+ table = ""
85
+
86
+ return vis_rgb, summary, table
87
+
88
+
89
+ # ── UI ─────────────────────────────────────────────────────────────────────
90
+
91
+ DESCRIPTION = """
92
+ # πŸš— Paint Defect Detector
93
+
94
+ Upload a photo of a car body panel to detect paint defects using a sliding-window
95
+ **EfficientNetV2-S** classifier. The model returns a heatmap overlay with bounding
96
+ boxes around defective regions.
97
+
98
+ > **Note:** A trained checkpoint (`checkpoints/best.pt`) must be present.
99
+ """
100
+
101
+ with gr.Blocks(title="Paint Defect Detector", theme=gr.themes.Soft()) as demo:
102
+ gr.Markdown(DESCRIPTION)
103
+
104
+ with gr.Row():
105
+ with gr.Column(scale=1):
106
+ img_input = gr.Image(label="Car Body Panel Photo", type="numpy")
107
+ vin_input = gr.Textbox(label="VIN (optional)", placeholder="e.g. XTA210930Y2837465")
108
+ threshold = gr.Slider(
109
+ minimum=0.1, maximum=0.9, value=C.DEFECT_THRESHOLD, step=0.05,
110
+ label="Defect Threshold",
111
+ info="Patch probability above this value is marked as defective."
112
+ )
113
+ run_btn = gr.Button("πŸ” Analyze", variant="primary")
114
+
115
+ with gr.Column(scale=1):
116
+ img_output = gr.Image(label="Visualization (Heatmap + Bounding Boxes)", type="numpy")
117
+ verdict_md = gr.Markdown(label="Result")
118
+ table_md = gr.Markdown(label="Defect Regions")
119
+
120
+ run_btn.click(
121
+ fn=run_inference,
122
+ inputs=[img_input, vin_input, threshold],
123
+ outputs=[img_output, verdict_md, table_md],
124
+ )
125
+
126
+ gr.Examples(
127
+ examples=[],
128
+ inputs=[img_input],
129
+ label="Examples"
130
+ )
131
+
132
+ if __name__ == "__main__":
133
+ demo.launch()