itsgokul02 commited on
Commit
6e22382
·
verified ·
1 Parent(s): b0482bf

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +164 -0
  2. best_model.pth +3 -0
app.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+ import gradio as gr
4
+
5
+ # ================= FIXED CONFIG =================
6
+ RUST_SCORE_THRESH = 0.45
7
+
8
+ # GrabCut rectangle (tower prior)
9
+ GC_LEFT = 0.20
10
+ GC_RIGHT = 0.80
11
+ GC_TOP = 0.02
12
+ GC_BOTTOM = 0.98
13
+
14
+ # Sky HSV bounds
15
+ SKY_LOWER = (80, 20, 40)
16
+ SKY_UPPER = (140, 255, 255)
17
+
18
+ GROUND_FRAC = 0.15
19
+ GRABCUT_ITERS = 10
20
+ TOWER_MORPH_K = 5
21
+ RUST_MORPH_K = 7
22
+
23
+ # Rust scoring weights
24
+ RUST_HUE_CENTER = 15
25
+ HUE_WIDTH = 0.20
26
+ W_A, W_H, W_S, W_T, W_L = 0.38, 0.22, 0.15, 0.20, 0.05
27
+ # ================================================
28
+
29
+
30
+ def remove_sky_mask(img):
31
+ hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
32
+ sky = cv2.inRange(hsv, np.array(SKY_LOWER), np.array(SKY_UPPER))
33
+ return (sky == 0).astype(np.uint8)
34
+
35
+
36
+ def remove_ground_mask(img):
37
+ h, w = img.shape[:2]
38
+ m = np.ones((h, w), np.uint8)
39
+ cut = int(h * GROUND_FRAC)
40
+ m[h - cut:h, :] = 0
41
+ return m
42
+
43
+
44
+ def grabcut_tower_mask(img, non_sky, non_ground):
45
+ h, w = img.shape[:2]
46
+
47
+ mask = np.full((h, w), cv2.GC_PR_BGD, np.uint8)
48
+ mask[non_sky == 0] = cv2.GC_BGD
49
+ mask[non_ground == 0] = cv2.GC_BGD
50
+
51
+ x1, x2 = int(w * GC_LEFT), int(w * GC_RIGHT)
52
+ y1, y2 = int(h * GC_TOP), int(h * GC_BOTTOM)
53
+
54
+ area = mask[y1:y2, x1:x2]
55
+ area[non_ground[y1:y2, x1:x2] == 1] = cv2.GC_PR_FGD
56
+ mask[y1:y2, x1:x2] = area
57
+
58
+ bgdModel = np.zeros((1, 65), np.float64)
59
+ fgdModel = np.zeros((1, 65), np.float64)
60
+
61
+ cv2.grabCut(img, mask, None, bgdModel, fgdModel, GRABCUT_ITERS, cv2.GC_INIT_WITH_MASK)
62
+
63
+ fg = ((mask == cv2.GC_FGD) | (mask == cv2.GC_PR_FGD)).astype(np.uint8)
64
+
65
+ k = np.ones((TOWER_MORPH_K, TOWER_MORPH_K), np.uint8)
66
+ fg = cv2.morphologyEx(fg, cv2.MORPH_CLOSE, k, iterations=2)
67
+ fg = cv2.morphologyEx(fg, cv2.MORPH_OPEN, k, iterations=1)
68
+
69
+ return fg
70
+
71
+
72
+ def rust_score_map(img):
73
+ lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB).astype(np.float32)
74
+ L, A = lab[:, :, 0], lab[:, :, 1]
75
+
76
+ A_n = (A - A.min()) / (A.max() - A.min() + 1e-6)
77
+ L_n = (L - L.min()) / (L.max() - L.min() + 1e-6)
78
+
79
+ hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV).astype(np.float32)
80
+ H, S = hsv[:, :, 0] / 179.0, hsv[:, :, 1] / 255.0
81
+
82
+ rust_center = RUST_HUE_CENTER / 179.0
83
+ hue_score = 1.0 - np.clip(np.abs(H - rust_center) / HUE_WIDTH, 0, 1)
84
+
85
+ gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
86
+ tex = np.abs(cv2.Laplacian(gray, cv2.CV_32F))
87
+ tex_n = (tex - tex.min()) / (tex.max() - tex.min() + 1e-6)
88
+
89
+ score = (
90
+ W_A * A_n +
91
+ W_H * hue_score +
92
+ W_S * S +
93
+ W_T * tex_n +
94
+ W_L * (1.0 - np.abs(L_n - 0.55))
95
+ )
96
+
97
+ return np.clip(score, 0, 1)
98
+
99
+
100
+ def postprocess(m):
101
+ k = np.ones((RUST_MORPH_K, RUST_MORPH_K), np.uint8)
102
+ m = cv2.morphologyEx(m, cv2.MORPH_CLOSE, k, iterations=2)
103
+ m = cv2.morphologyEx(m, cv2.MORPH_OPEN, k, iterations=1)
104
+ return m
105
+
106
+
107
+ def run(img_rgb):
108
+ if img_rgb is None:
109
+ return None, None, None, None, "Upload an image."
110
+
111
+ img = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2BGR)
112
+
113
+ non_sky = remove_sky_mask(img)
114
+ non_ground = remove_ground_mask(img)
115
+ tower = grabcut_tower_mask(img, non_sky, non_ground)
116
+
117
+ roi = tower * non_sky * non_ground
118
+ score = rust_score_map(img)
119
+
120
+ rust = ((score >= RUST_SCORE_THRESH).astype(np.uint8)) * roi
121
+ rust = postprocess(rust)
122
+
123
+ overlay = img.copy()
124
+ overlay[rust == 1] = [0, 0, 255]
125
+
126
+ rust_px = int(rust.sum())
127
+ roi_px = int(roi.sum())
128
+ pct = 100 * rust_px / max(1, roi_px)
129
+
130
+ stats = (
131
+ f"Rust threshold: {RUST_SCORE_THRESH}\n"
132
+ f"Rust pixels: {rust_px}\n"
133
+ f"ROI pixels: {roi_px}\n"
134
+ f"Rust on tower ROI: {pct:.2f}%"
135
+ )
136
+
137
+ return (
138
+ cv2.cvtColor(tower * 255, cv2.COLOR_GRAY2RGB),
139
+ cv2.cvtColor(rust * 255, cv2.COLOR_GRAY2RGB),
140
+ cv2.cvtColor(overlay, cv2.COLOR_BGR2RGB),
141
+ cv2.applyColorMap((score * 255).astype(np.uint8), cv2.COLORMAP_TURBO),
142
+ stats
143
+ )
144
+
145
+
146
+ with gr.Blocks(title="Tower Rust Detection") as demo:
147
+ gr.Markdown("## Tower Rust Detection (Fully Automatic)\nUpload an image and click **Run**.")
148
+
149
+ inp = gr.Image(type="numpy", label="Input Image")
150
+ run_btn = gr.Button("Run", variant="primary")
151
+
152
+ with gr.Row():
153
+ out_tower = gr.Image(label="Tower Mask")
154
+ out_rust = gr.Image(label="Rust Mask")
155
+ with gr.Row():
156
+ out_overlay = gr.Image(label="Overlay")
157
+ out_heat = gr.Image(label="Rust Score Heatmap")
158
+
159
+ stats = gr.Textbox(label="Stats", lines=5)
160
+
161
+ run_btn.click(run, inputs=inp, outputs=[out_tower, out_rust, out_overlay, out_heat, stats])
162
+
163
+ if __name__ == "__main__":
164
+ demo.launch()
best_model.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8198e6f67a81c4d1f651e58a65c3cba804c8eb1cca6276dbaf65603cb3f6c0c8
3
+ size 97919828